how do I fix this error? ReferenceError: totalSupply is not defined - error-handling

Im using a course, and I got this error:
ReferenceError: totalSupply is not defined
and Idk what it means by that, cause I never got this error before.
can somebody help me fix this error? thanks
and this is my code:
const { assert } = require("chai");
const KryptoBird = artifacts.require("KryptoBird");
// check for chai
require('chai')
.use(require('chai-as-promised'))
.should()
contract('KryptoBird', (accounts) => {
let contract
before( async () => {
contract = await KryptoBird.deployed()
})
describe('deployment', async() => {
it("deploys successfully", async () => {
const address = contract.address;
assert.notEqual(address, '')
assert.notEqual(address, null)
assert.notEqual(address, undefined)
assert.notEqual(address, 0x0)
})
it('has a name', async() => {
const name = await contract.name()
assert.equal(name, 'KryptoBird')
})
it('has a symbol', async() => {
const symbol = await contract.symbol()
assert.equal(symbol, 'KBIRDZ')
})
})
describe('minting', async ()=> {
it('creates a new token', async ()=> {
const result = await contract.mint('https...1')
const totalSupply = await contract.totalSupply();
assert.equal(totalSupply, 1)
const event = result.logs[0].args
assert.equal(event._from, '0x0000000000000000000000000000000000000000', 'from is the contract')
assert.equal(event._to, accounts[0], 'to is msg.sender')
await contract.mint('https...1').should.be.rejected
})
})
describe('indexing', async()=> {
it('lists KryptoBirdz', async()=> {
// Mint three new tokens
await contract.mint('https...2')
await contract.mint('https...3')
await contract.mint('https...4')
const totalSupply = await contract.totalSupply()
})
let result = []
let KryptoBird
for(i = 1; i <= totalSupply; i++) {
KryptoBird = await contract.kryptoBirdz(i)
result.push(KryptoBird)
}
let expected = ['https...1','https...2','https...3','https...4']
assert.equal(result.join(','), expected.join(','))
})
})
if u need another contract, just tell me, and if u could help me, thanks so much, because I need to finish this today. I've been trying to fix this for 2 hours, it didnt work. so please, if u could help me, it would mean a LOT to me.
here:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import './ERC721Connecter.sol';
contract KryptoBird is ERC721Connecter {
string[] public kryptoBirdz;
mapping(string => bool) _kryptoBirdzExists;
function mint(string memory _kryptoBird) public {
require(!_kryptoBirdzExists[_kryptoBird],
'Error - kryptoBird already exists');
// this is deprecated - uint _id = KryptoBirdz.push(_kryptoBird);
kryptoBirdz.push(_kryptoBird);
uint _id = kryptoBirdz.length - 1;
// .push no logner returns the length but a ref to the added element
_mint(msg.sender, _id);
_kryptoBirdzExists[_kryptoBird]=true;
}
constructor() ERC721Connecter('KryptoBird','KBIRDZ')
{}
}

Related

Mock, jest and time

I read some tips on how to mock your request/response in Express framework in the blog:
https://codewithhugo.com/express-request-response-mocking/. However, I have no clue how to mock the controller below.
export const healthCheck = async (req, res, next) => {
log("debug", "healthCheck controller called");
const healthcheck = {
uptime: process.uptime(),
message: "Server is running!",
now_timestamp: Date.now()
};
try {
res.send(healthcheck);
} catch (error) {
healthcheck.message = error;
res.status(503).send();
}
};
I am glad to share my efforts below. My suspicion is that I must mock class Date as well.
import {
healthCheck
} from "../healthcheck.js";
const mockRequest = () => {
const req = {}
req.body = jest.fn().mockReturnValue(req)
req.params = jest.fn().mockReturnValue(req)
return req
};
const mockResponse = () => {
const res = {}
res.get = jest.fn().mockReturnValue(res)
res.send = jest.fn().mockReturnValue(res)
res.status = jest.fn().mockReturnValue(res)
res.json = jest.fn().mockReturnValue(res)
return res
};
const mockNext = () => {
return jest.fn()
};
describe("healthcheck", () => {
afterEach(() => {
// restore the spy created with spyOn
jest.restoreAllMocks();
});
it("should call mocked log for invalid from scaler", async () => {
let req = mockRequest();
let res = mockResponse();
let next = mockNext();
await healthCheck(req, res, next);
expect(res.send).toHaveBeenCalledTimes(1)
expect(res.send.mock.calls.length).toBe(1);
});
});

Can't get signer

Trying to read a transfer event from the ENS contract.
const listenToEvent = () => {
const contract = new ethers.Contract(
"0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85",
erc721Abi,
signer
);
contract.on("Transfer", (from, to, tokenId, event) => {
let data = {
from,
to,
tokenId: tokenId.toString(),
event,
};
console.log(data);
});
};
const balance = async (tokenAddress) => {
const contract = new ethers.Contract(tokenAddress, erc721Abi, signer);
const balance = await contract.balanceOf(account);
console.log(balance.toString());
};
const connect = async () => {
if (typeof window.ethereum !== "undefined") {
const accounts = await window.ethereum.request({
method: "eth_requestAccounts",
});
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
setSigner(signer);
listenToEvent();
setAccount(accounts[0]);
} else {
console.log("Please install metamask.");
}
};
In my console it gives me this error:
Uncaught (in promise) Error: events require a provider or a signer with a provider (operation="once", code=UNSUPPORTED_OPERATION, version=contracts/5.7.0)

How to transfer reward token to contract in Test Case

I am working on a sample contract which should provide a reward for the user. The winner gets the reward as Token.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.5;
contract LeagueWinners {
struct Winner {
bool exists;
bool claimed;
uint256 reward;
}
mapping(address=>Winner) public winners;
mapping (address => bool) private AuthAccounts;
IERC20 private rewardTokenAddr;
modifier onlyAuthAccounts() {
require(AuthAccounts[msg.sender], "Auth: caller is not the authorized");
_;
}
constructor (address _rewardTokenAddr) {
rewardTokenAddr = IERC20(_rewardTokenAddr);
AuthAccounts[msg.sender] = true;
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
function addWinner(address _address, uint256 _amount ) public {
Winner storage winner = winners[_address];
winner.exists = true;
winner.reward = _amount;
}
function claimPrize() public {
Winner storage winner = winners[msg.sender];
require(winner.exists, "Not a winner");
require(!winner.claimed, "Winner already claimed");
winner.claimed = true;
rewardTokenAddr.safeTransfer(msg.sender, winner.tokenAmount);
}
}
Test cases is failing when the user is trying to claim the prize. I assume there is no reward token in the contract so its failing.
const { expect } = require("chai");
const { ethers } = require("hardhat");
const hre = require("hardhat");
describe("LeagueWinners", function () {
let rewardTokenAddr = "0xAddr.....";
before(async () => {
LeagueWinners = await ethers.getContractFactory("LeagueWinners");
leagueWiners = await LeagueWinners.deploy(rewardTokenAddr);
await leagueWiners.deployed();
[owner, winner1, winner2, nonwinner] = await ethers.getSigners();
});
it("Claim Tokens to be deployed and verify owner", async function () {
expect(await leagueWiners.owner()).to.equal(owner.address);
});
it("Add Winner", async function () {
winner = await leagueWiners
.connect(owner)
.addWinner(
"winner1.address",
"50000000000000000000"
);
});
it("Confirm Winner Added with proper reward", async function () {
winner = await leagueWiners.winners(winner1.address);
expect(winner.reward).to.equal("50000000000000000000");
});
it("Non winner cannot claim", async function () {
await expect(
leagueWiners.connect(nonwinner).claimReward()).to.be.revertedWith("Not a winner");
});
it("Winner to claim", async function () {
await leagueWiners.connect(winner1).claimPrize();
winner = await leagueWiners.winners(winner1.address);
expect(winner.claimed).to.equal(true);
});
});
Error:
Error: VM Exception while processing transaction: reverted with reason string 'Address: call to non-contract'
This line is causing the error
await leagueWiners.connect(winner1).claimReward();
From the smart contract source that you provided I see that the name of function is claimPrize() not claimReward()
Maybe can work if you change to:
leagueWiners.connect(winner1).claimPrize();

Test cases failing due to custom modifier

I am new to solidity and trying to code it on my own before using open Zepplin plugins.
Here is the contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.5;
contract LeagueWinners {
struct Winner {
bool exists;
bool claimed;
uint256 reward;
}
mapping(address=>Winner) public winners;
mapping (address => bool) private AuthAccounts;
modifier onlyAuthAccounts() {
require(AuthAccounts[msg.sender], "Auth: caller is not the authorized");
_;
}
constructor () {
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
function addWinner(address _address, uint256 _amount ) public {
Winner storage winner = winners[_address];
winner.exists = true;
winner.reward = _amount;
}
}
I know we have the Ownable plugin from openzepplin. but just trying with my own modifier as I want 2 users to add winners.
The contract works well. but I am facing issues in writing test cases.
const { expect } = require("chai");
const { ethers } = require("hardhat");
const hre = require("hardhat");
describe("LeagueWinners", function () {
before(async () => {
LeagueWinners = await ethers.getContractFactory("LeagueWinners");
leagueWiners = await LeagueWinners.deploy();
await leagueWiners.deployed();
[owner] = await ethers.getSigners();
});
it("Claim Tokens to be deployed and verify owner", async function () {
expect(await leagueWiners.owner()).to.equal(owner.address);
});
it("Add Winner", async function () {
winner = await leagueWiners
.connect(owner)
.addWinner(
"_addr",
"50000000000000000000"
);
});
});
Add winner is getting failed, not sure how to pass the AuthAccounts. Any guidance will be great help
Error
Error: VM Exception while processing transaction: reverted with reason string 'Auth: caller is not the authorized'
You don't pass any addresses to the constructor here:
constructor () {
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
You need to add the _addr_1 and _addr_2 into the constructor like this:
constructor (address _addr_1, address _addr_2) {
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
The compiler shouldn't let you compile this contract so I'm not sure how it lets you deploy it.
Then in your test you need to pass the arguments like this:
before(async () => {
LeagueWinners = await ethers.getContractFactory("LeagueWinners");
leagueWiners = await LeagueWinners.deploy(addr1, addr2); // HERE
await leagueWiners.deployed();
[owner] = await ethers.getSigners();
});
After spending a few days, made a solution in this way.
constructor () {
AuthAccounts[msg.sender] = true;
AuthAccounts[_addr_1] = true;
AuthAccounts[_addr_2] = true;
}
As i was hardcoding other addresses, it was not possible to get signer info in the test cases. Passing msg.sender in AuthAccounts helped to achieve that and test cases got passed.
Let me know if there are any other work arounds.

Jest testing of async middleware for authentication

I'm using a static array to scaffold a user table, prior to refactoring with actual postgres db and some fetch()-ing code. At present, the tests work, but obviously they are working synchronously. Here's the placeholder API code:
// UserAPI.js
let findUserById = (credentials = {}) => {
const { userId } = credentials
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
And an example test as follows:
// excerpt from TokenAuth.test.js
const UserAPI = require('../lib/UserAPI')
describe('With TokenAuth middleware', () => {
beforeEach(() => {
setStatus(0)
})
it('should add user to req on authorised requests', () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})
})
This runs fine, and along with other tests gives me the coverage I want. However, I now want to check that the tests will deal with the async/await nature of the fetch() code I'm going to use for the proper UserAPI.js file. So I re-write the placeholder code as:
// UserAPI.js with added async/await pauses ;-)
let findUserById = async (credentials = {}) => {
const { userId } = credentials
// simulate url resolution
await new Promise(resolve => setTimeout(() => resolve(), 100)) // avoid jest open handle error
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
... at which point I start getting some lovely failures, due I think it's returning unresolved promises.
My problem is two-fold:
How should I alter the UserAPI.test.js tests to deal with the new async nature of findUserByCredentials() ?
Am I ok in my assumption that ExpressJS is happy with async functions as request handlers? Specifically, due to the async nature ofUserAPI.findUserByCredentials is this ok?
Main App.js uses curried UserAPI.byId() for the findUserById.
// App.js (massively simplified)
const express = require('express')
const TokenAuth = require('./middleware/TokenAuth')
const RequireAuth = require('./middleware/RequireAuth')
const UserAPI = require('./lib/UserAPI')
let router = express.Router()
const app = express()
app.use(TokenAuth(UserAPI.byId))
app.use(RequireAuth)
app.use('/users', UserRouter)
module.exports = app
My TokenAuth middleware would now run along these lines:
// TokenAuth.js (simplified)
const jwt = require('jsonwebtoken')
require('dotenv').config()
const signature = process.env.SIGNATURE
let TokenAuth = findUserById => async (req, res, next) => {
let header = req.headers.authorization || ''
let [type, token] = header.split(' ')
if (type === 'Bearer') {
let payload
try {
payload = jwt.verify(token, signature)
} catch (err) {
res.sendStatus(401)
return
}
let user = await findUserById(payload)
if (user) {
req.user = user
} else {
res.sendStatus(401)
return
}
}
next()
}
module.exports = TokenAuth
A partial answer us simply to add an async/await on the middleware call:
it('should add user to req on authorised requests', async () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
await myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})