It seems like you are trying to use the wrong getAmountsOut function:
// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'PancakeLibrary: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
This function is marked as internal so it can only be called inside this contract or any contract that derived from the PancakeRouter contract. The right function to call would be this which is also located in the PancakeRouter contract:
function getAmountsOut(uint amountIn, address[] memory path) public pure virtual override returns (uint[] memory amounts) {
return PancakeLibrary.getAmountsOut(factory, amountIn, path);
}
--
To give you an example on how to use it with Javascript:
const router = new ethers.Contract('0x10ED43C718714eb63d5aA57B78B54704E256024E', [
'function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)',
'function getAmountsOut(uint amountIn, address[] memory path) public pure virtual override returns (uint[] memory amounts)'
], account);
const amountIn = 1
const fromTokenAddress = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c' //BNB
const toTokenAddress = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56' //BUSD
let amountOuts = await router.getAmountsOut(amountIn, [fromTokenAddress, toTokenAddress])
-> The first array element of amountOuts will be the amountIn you sent
EDIT:
Decimal values can be send using the wei unit representation. Just multiply the value you want to send with 10 ** 18 like in the following example:
22.5 BNB -> 22.5 * 10 ** 18 = 22500000000000000000
There are lots of helpful libraries that can help you handling those numbers and providing functions for calculation. For example ethers.js includes such implementation which can be easily used just beware of the version you are using because the usage of BigNumbers in ethers.js is different in version.
The length of a public array is not exposed by default in solidity.
You can either define a specific solidity function for it :
function getLength() public view returns (uint256) {
return functionCaller.length;
}
And call that function in your test.
Or directly from ethers.js, read the storage slot of your array (in your example it's in storage slot 0) which holds its length (see the documentation). Be careful though, changing your contract's storage layout may change the storage slot of the array, thus, invalidating your test.
describe("Validate length on push", function () {
it("Should increment the length after a push is done", async function () {
const contract = await ethers.getContractFactory("A");
const instance = await contract.deploy();
await instance.deployed();
// Read storage slot 0 holding the length of the array
const initialLength = ethers.BigNumber.from(await ethers.provider.getStorageAt(instance.address, 0));
expect(initialLength.eq(0)).to.equal(true);
await instance.test();
// Read storage slot 0 holding the length of the array
const newLength = ethers.BigNumber.from(await ethers.provider.getStorageAt(instance.address, 0));
expect(newLength.eq(1)).to.equal(true);
});
});
I hope that answers your question.
Best Answer
You would do so as follows:
Where both
inputAmount
andethersValue
are of type BigNumber.You still need to add checks on the contract side to assert that user sent the correct
msg.value
(correct amount of Ethers) to the contract that are needed to buy the providedinputAmount
.