Mock with Waffle return undefined - solidity

I have two contracts, one returns a static value (10)
I'd like to mock this value and return 2 (for instance), I'm trying with "mock" according to the documentation, but I still get 10
my test is:
describe('test', () => {
async function setup() {
const [sender, receiver] = new MockProvider().getWallets();
const mockGetEtherPrice = await deployMockContract(sender, GetEtherPrice.abi);
const contractFactory = new ContractFactory(NumbersMarketContract.abi, NumbersMarketContract.bytecode, sender);
console.log(mockGetEtherPrice);
const contract = await contractFactory.deploy();
return {sender, receiver, contract, mockGetEtherPrice};
}
it('returns false if the wallet has less then 1000000 coins', async () => {
const {contract, mockGetEtherPrice} = await setup();
await mockGetEtherPrice.mock.getPriceMocked.returns(2);
console.log(await contract.check())
expect(await contract.check()).to.be.equal(10);
});
});
My GetEtherPrice contract is:
contract GetEtherPrice {
function getPrice() public pure returns(uint256){
return getPriceMocked();
}
function getPriceMocked() public pure returns(uint256){
return 10;
}
}
In the main contract, I use 'is' to import my contract like:
contract NumbersMarketContract is GetEtherPrice
....
function check() public pure returns (uint256){
return getPrice();
}

Related

How to receive a value returned by a Solidity smart contract transacting function?

I am writing an NFT smart contract which I am going to test via Hardhat and deploy on RSK.
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract MyNFT is ERC721URIStorage {
uint private _counter;
address private _owner;
constructor() ERC721("My NFT", "MNFT") {
_owner = msg.sender;
}
function owner() public view returns (address) {
return _owner;
}
function mintNFT(address recipient, string memory tokenURI)
public returns (uint256)
{
require(msg.sender == owner(), "Only owner is allowed to mint");
uint newItemId = ++_counter;
ERC721._mint(recipient, newItemId);
ERC721URIStorage._setTokenURI(newItemId, tokenURI);
return newItemId;
}
}
Here I have two public functions: owner and mintNFT both returning some values. In my tests I would like to read the return values coming from these two functions. These are the tests I am running on Hardhat:
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("My NFT", () => {
let deployer;
let myNFT;
// deploy NFT before the tests
before(async () => {
[deployer] = await ethers.getSigners();
const MyNFT = await ethers.getContractFactory('MyNFT');
myNFT = await MyNFT.deploy();
await myNFT.deployed();
});
describe('Receiving a value returned by a view function', () => {
it('The deployer should be the s/c owner', async () => {
const owner = await myNFT.owner();
expect(owner).to.equal(deployer.address);
});
});
describe('Receiving a value returned by a transacting function', () => {
it('Should return a correct ID of the newly minted item', async () => {
const newMintItem = {
id: 1,
uri: 'ipfs://Qme3QxqsJih5psasse4d2FFLFLwaKx7wHXW3Topk3Q8b14',
};
const newItemId = await myNFT.mintNFT(deployer.address, newMintItem.uri);
expect(newItemId).to.equal(newMintItem.id);
});
});
});
In the case of the owner function I get what I expect: It returns my account address, and the first test passes successfully. However, when it comes to the mintNFT function, I don't get what I expect: Instead of the newly created item ID I get something very different and my second test fails.
Why do two very similar tests give me different results? How do I get a return value from a function that sends a transaction?
For reference, this is the hardhat.config.js file I'm using:
require("#nomiclabs/hardhat-waffle");
module.exports = {
solidity: "0.8.4",
defaultNetwork: 'rskregtest',
networks: {
rskregtest: {
chainId: 33,
url: 'http://localhost:4444',
},
},
};
Values returned from a transaction are not available outside of EVM.
You can either emit an event, or create a public view getter function of the value.
contract MyNFT is ERC721URIStorage {
// `public` visibility autogenerates view function named `_counter()`
uint public _counter;
event NFTMinted(uint256 indexed _id);
function mintNFT(address recipient, string memory tokenURI)
public returns (uint256)
{
// ...
emit NFTMinted(newItemId);
return newItemId;
}
}
it('Should return a correct ID of the newly minted item', async () => {
const newMintItem = {
id: 1,
uri: 'ipfs://Qme3QxqsJih5psasse4d2FFLFLwaKx7wHXW3Topk3Q8b14',
};
// testing the emitted event
await expect(myNFT.mintNFT(deployer.address, newMintItem.uri))
.to.emit(myNFT, "NFTMinted")
.withArgs(newMintItem.id);
// testing the getter value
const counter = await myNFT._counter();
expect(counter).to.equal(newMintItem.id);
});
Docs: https://ethereum-waffle.readthedocs.io/en/latest/matchers.html#emitting-events
You can not directly receive a return value coming from a function that you are sending a transaction to off-chain. You can only do so on-chain - i.e. when one SC function invokes another SC function.
However, in this particular case, you can obtain the value through events, as the ERC721 specification includes a Transfer event:
/// #dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
In Ethers.js, which you are already using in your hardhat tests, instead of smart contract function return value, you get a transaction response object returned on this line:
const txResponse = await myNFT.mintNFT(deployer.address, newMintItem.uri);
Next you need to get a transaction receipt by calling wait on txResponse:
const txReceipt = await txResponse.wait();
In turn, txReceipt contains an events array which includes all events emitted by your transaction. In this case, expect it to include a single Transfer event indicating the first minted item transfer from the zero address to your account address. Get this event by extracting the first element from the events array:
const [transferEvent] = txReceipt.events;
Next take tokenId property from the transferEvent arguments and this will be the Id of your newly minted NFT:
const { tokenId } = transferEvent.args;
The whole test should look as follows:
describe('Receiving a value returned by a transacting function', () => {
it('Should return a correct ID of the newly minted item', async () => {
const newMintItem = {
id: 1,
uri: 'ipfs://QmY6KX35Rg25rnaffmZzGUFb3raRhtPA5JEFeSSWQA4GHL',
};
const txResponse = await myNFT.mintNFT(deployer.address, newMintItem.uri);
const txReceipt = await txResponse.wait();
const [transferEvent] = txReceipt.events;
const { tokenId } = transferEvent.args;
expect(tokenId).to.equal(newMintItem.id);
});
});

Duplicate identifier 'alpha'.deno-ts(2300) Unexpected keyword or identifier

I am trying to use Alpha Vantage NPM package inside my Deno application. I tried to use SkyPack version of it. But it gives me the following error:
Duplicate identifier 'alpha'.deno-ts(2300)
Unexpected keyword or identifier.
This is the code I am using:
import alphavantageTs from 'https://cdn.skypack.dev/alphavantage-ts';
export class StockTimeSeries{
alpha = new alphavantageTs ("ASLDVIWXGEWFWNZG");
alpha.stocks.intraday("msft").then((data: any) => {
console.log(data);
});
alpha.stocks.batch(["msft", "aapl"]).then((data: any) => {
console.log(data);
});
alpha.forex.rate("btc", "usd").then((data: any) => {
console.log(data);
});
alpha.crypto.intraday("btc", "usd").then((data: any) => {
console.log(data);
});
alpha.technicals.sma("msft", "daily", 60, "close").then((data: any) => {
console.log(data);
});
alpha.sectors.performance().then((data: any) => {
console.log(data);
});
}
It looks like SkyPack is responding with a 401 for one of the sub-dependencies for that module. I'm also not even sure it's compatible with Deno.
That said, here's the repo source for the module, and here's the documentation for the API. It looks like it's just a simple REST API which discriminates requests by query parameters, so you can make your own Deno client without too much effort using that module as a template. I'll give you some starter code:
TS Playground
export type Params = NonNullable<ConstructorParameters<typeof URLSearchParams>[0]>;
class AlphaVantageNS { constructor (protected readonly api: AlaphaVantage) {} }
class Forex extends AlphaVantageNS {
rate (from_currency: string, to_currency: string) {
return this.api.query({
function: 'CURRENCY_EXCHANGE_RATE',
from_currency,
to_currency,
});
}
}
export class AlaphaVantage {
#token: string;
constructor (token: string) {
this.#token = token;
}
async query <Result = any>(params: Params): Promise<Result> {
const url = new URL('https://www.alphavantage.co/query');
const usp = new URLSearchParams(params);
usp.set('apikey', this.#token);
url.search = usp.toString();
const request = new Request(url.href);
const response = await fetch(request);
if (!response.ok) throw new Error('Response not OK');
return response.json();
}
forex = new Forex(this);
}
// Use:
const YOUR_API_KEY = 'demo';
const alpha = new AlaphaVantage(YOUR_API_KEY);
alpha.forex.rate('BTC', 'USD').then(data => console.log(data));

Understanding truffle test

I am following a tutorial to create a smart contract using truffle. I would like to have a better understanding about the test created in the tutorial.
This is one of the tests:
it("increases myDonationsCount", async () => {
const currentDonationsCount = await fundraiser.myDonationsCount(
{from: donor}
);
await fundraiser.donate({from: donor, value});
const newDonationsCount = await fundraiser.myDonationsCount(
{from: donor}
);
assert.equal(
1,
newDonationsCount - currentDonationsCount,
"myDonationsCount should increment by 1");
})
where does this object come from? {from: donor, value}
And for this test:
it("throws an error when called from a different account", async () =>{
try {
await fundraiser.setBeneficiary(newBeneficiary, {from: accounts[3]});
assert.fail("withdraw was not restricted to owners")
} catch(err) {
const expectedError = "Ownable: caller is not the owner"
const actualError = err.reason;
assert.equal(actualError, expectedError, "should not be permitted")
}
})
In the 3rd line from the above test they are passing 2 parameters fundraiser.setBeneficiary(newBeneficiary, {from: accounts[3]});.
How is this possible if the original function only receives one?
The function:
function setBeneficiary(address payable _beneficiary) public onlyOwner {
beneficiary = _beneficiary;
}
It's the transaction params.
Truffle allows you to override the default transaction params by specifying the overrides in the last argument, after you've passed all arguments defined in the Solidity function.
Docs: https://www.trufflesuite.com/docs/truffle/getting-started/interacting-with-your-contracts#making-a-transaction

How to mock koa context in a function that returns a function with context parameter

I have a file, myFunction.ts that defines and exports one function:
export function MyFunction() {
return async (ctx: Koa.Context) => {
//some work happens in here
};
}
This function gets called in a Koa middleware file and inherits the ctx from previous middleware. How does one create a mock ctx to test MyFunction() in this case?
I use Shopify's library #shopify/jest-koa-mocks. They use Koa's createContext under the hood if you want to explore building it yourself.
import { createMockContext } from '#shopify/jest-koa-mocks';
import { myFunction } from './myFunction.js';
describe('middleware being tested', () => {
let ctx;
let myMiddleware;
beforeEach(() => {
ctx = createMockContext();
ctx.addAnythingYouWant = jest.fn();
myMiddleware = myFunction();
});
test('calls function addAnythingYouWant', async () => {
await myMiddleware(ctx);
expect(ctx.addAnythingYouWant).toHaveBeenCalledTimes(1);
});
});

TypeError: Cannot read property 'call' of undefined when testing solidity contract

I have a problem like this. I am building a dapp using Ethereum while following a video tutorial.
This is my smart contract.
pragma solidity ^0.4.0;
contract SimpleWallet {
address owner;
mapping(address => bool) isAllowedToSendsFundsMapping;
event deposit(address _sender, uint amount);
event withdraw(address _sender, uint amount, address _benificiary);
function SimpleWallet()public{
owner= msg.sender;
}
function (){
if(msg.sender == owner || isAllowedToSendsFundsMapping[msg.sender]== true){
deposit(msg.sender, msg.value);
}else{
throw;
}
}
function sendFunds(uint amount, address receiver) returns (uint){
if(msg.sender == owner || isAllowedToSendsFundsMapping[msg.sender]){
if(this.balance>= amount){
if(!receiver.send(amount)){
throw;
}
withdraw(msg.sender, amount, receiver);
return this.balance;
}
}
}
function allowAddressToSendMoney(address _address){
if(msg.sender == owner){
isAllowedToSendsFundsMapping[_address]=true;
}
}
function disallowAddressToSendMoney(address _address){
if(msg.sender == owner){
isAllowedToSendsFundsMapping[_address]=false;
}
}
function isAllowedToSend(address _address) constant returns (bool){
return isAllowedToSendsFundsMapping[_address]|| msg.sender == owner;
}
function killWallet(){
if(msg.sender == owner){
selfdestruct(owner);
}
}
}
Here I am providing the testing file.
var SimpleWallet = artifacts.require('./SimpleWallet.sol')
contract('SimpleWallet', function (accounts) {
it('the owner is allowed to send funds', function () {
var myContract = SimpleWallet.deployed()
return myContract.isAllowedToSend.call(accounts[0]).then(function (isAllowed) {
assert.equals(isAllowed, true, 'the owner should have been allowed to send funds')
})
})
})
But when I hit truffle test in the console it gives me an error like this.
TypeError: Cannot read property 'call' of undefined
I recheck the code with the video but both codes are similar. It working correctly in the video but in my computer, it is not working correctly. And I google it but i was not able to find a suitable answer to my problem. can someone help me to solve this problem? Thank You.
Fixed and simplified your test file, here you go:
const SIMPLE_WALLET = artifacts.require('SimpleWallet.sol');
contract('SimpleWallet', function (accounts) {
let simpleWallet;
beforeEach('setup contract for each test case', async () => {
simpleWallet = await SIMPLE_WALLET.new({from: accounts[0]})
})
it('should let owner to send funds', async () => {
const isAllowed = await simpleWallet.isAllowedToSend(accounts[0]);
assert(isAllowed);
})
})