getting error: Fail with error 'STF' UniswapV3 on swap - solidity

Created a contract a basic one to deploy on the Mumbai BC.
The same one of uni swaps the basic one, just with different addresses. Since this is in Mumbai BC, so I created it with wmatic.
then after approving all the addresses, I get this error without any explanation or option to understand where it failed when i try to singleswap.
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
pragma abicoder v2;
import "hardhat/console.sol";
import '#uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
import '#uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
contract SwapExamples {
// For the scope of these swap examples,
// we will detail the design considerations when using
// `exactInput`, `exactInputSingle`, `exactOutput`, and `exactOutputSingle`.
// It should be noted that for the sake of these examples, we purposefully pass in the swap router instead of inherit the swap router for simplicity.
// More advanced example contracts will detail how to inherit the swap router safely.
ISwapRouter public immutable swapRouter;
address public constant WMATIC = 0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889;
address public constant WETH = 0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa;
// For this example, we will set the pool fee to 0.3%.
uint24 public constant poolFee = 3000;
constructor(ISwapRouter _swapRouter) {
swapRouter = _swapRouter;
}
/// #notice swapExactInputSingle swaps a fixed amount of WMATIC for a maximum possible amount of WETH
/// using the WMATIC/WETH 0.3% pool by calling `exactInputSingle` in the swap router.
/// #dev The calling address must approve this contract to spend at least `amountIn` worth of its WMATIC for this function to succeed.
/// #param amountIn The exact amount of WMATIC that will be swapped for WETH.
/// #return amountOut The amount of WETH received.
function swapExactInputSingle(uint256 amountIn) external returns (uint256 amountOut) {
// msg.sender must approve this contract
// Transfer the specified amount of WMATIC to this contract.
TransferHelper.safeTransferFrom(WMATIC, msg.sender, address(this), amountIn);
// Approve the router to spend WMATIC.
TransferHelper.safeApprove(WMATIC, address(swapRouter), amountIn);
// Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum.
// We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount.
ISwapRouter.ExactInputSingleParams memory params =
ISwapRouter.ExactInputSingleParams({
tokenIn: WMATIC,
tokenOut: WETH,
fee: poolFee,
recipient: msg.sender,
deadline: block.timestamp,
amountIn: amountIn,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
// The call to `exactInputSingle` executes the swap.
amountOut = swapRouter.exactInputSingle(params);
}
/// #notice swapExactOutputSingle swaps a minimum possible amount of WMATIC for a fixed amount of WETH.
/// #dev The calling address must approve this contract to spend its WMATIC for this function to succeed. As the amount of input WMATIC is variable,
/// the calling address will need to approve for a slightly higher amount, anticipating some variance.
/// #param amountOut The exact amount of WETH to receive from the swap.
/// #param amountInMaximum The amount of WMATIC we are willing to spend to receive the specified amount of WETH.
/// #return amountIn The amount of WMATIC actually spent in the swap.
function swapExactOutputSingle(uint256 amountOut, uint256 amountInMaximum) external returns (uint256 amountIn) {
// Transfer the specified amount of WMATIC to this contract.
TransferHelper.safeTransferFrom(WMATIC, msg.sender, address(this), amountInMaximum);
// Approve the router to spend the specifed `amountInMaximum` of WMATIC.
// In production, you should choose the maximum amount to spend based on oracles or other data sources to acheive a better swap.
TransferHelper.safeApprove(WMATIC, address(swapRouter), amountInMaximum);
ISwapRouter.ExactOutputSingleParams memory params =
ISwapRouter.ExactOutputSingleParams({
tokenIn: WMATIC,
tokenOut: WETH,
fee: poolFee,
recipient: msg.sender,
deadline: block.timestamp,
amountOut: amountOut,
amountInMaximum: amountInMaximum,
sqrtPriceLimitX96: 0
});
// Executes the swap returning the amountIn needed to spend to receive the desired amountOut.
amountIn = swapRouter.exactOutputSingle(params);
// For exact output swaps, the amountInMaximum may not have all been spent.
// If the actual amount spent (amountIn) is less than the specified maximum amount, we must refund the msg.sender and approve the swapRouter to spend 0.
if (amountIn < amountInMaximum) {
TransferHelper.safeApprove(WMATIC, address(swapRouter), 0);
TransferHelper.safeTransfer(WMATIC, msg.sender, amountInMaximum - amountIn);
}
}
}

I'm in the same point as you since two weeks. I don't solved the problem yet but I have more data useful for you:
I tried to do a swap on https://app.uniswap.org on mumbai network and I discovered that the SwapRouter address for mumbai maybe is wrong or is not the primary as they have on official uniswap website (I mean: 0xE592427A0AEce92De3Edee1F18E0157C05861564).
I don't know if they are using two addresses, but I tried two times and two times has passed for 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 as SwapRouter. You can check it if you try to do a swap on the website.
My tx example: https://mumbai.polygonscan.com/tx/0xa7e75b78ec8f5ae311d0252d0ad7412176ebe7f063df72a8f2c347543f8f2103

ok, finally after several days I achieved do a swap on mumbai with exactInputSingle! This test swap 0.5Wmatic for weth. I attach you my scripts:
TestSwap.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
pragma abicoder v2;
import '#uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol';
import "./SwapRouter02lib/ISwapRouter02.sol";
import "./SwapRouter02lib/IV3SwapRouter.sol";
import '#openzeppelin/contracts/token/ERC20/IERC20.sol';
contract TestSwap {
using LowGasSafeMath for uint256;
ISwapRouter02 public immutable uniswapRouter;
constructor(address _uniswapRouter) {
uniswapRouter = ISwapRouter02(_uniswapRouter);
}
function swapUniswap(
address token0,
address token1,
uint256 amount,
uint256 fee
) external returns (uint256 amountOut) {
require(IERC20(token0).transferFrom(msg.sender, address(this), amount),"STF v2");
require(IERC20(token0).approve(address(uniswapRouter), amount),"SA v2");
uint256 amountMin = LowGasSafeMath.add(amount, fee);
IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter.ExactInputSingleParams({
tokenIn: token0,
tokenOut: token1,
fee: uint24(fee),
recipient: msg.sender,
amountIn: amount,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
(bool success, bytes memory amountBytes) = address(uniswapRouter).call(
abi.encodeWithSelector(
IV3SwapRouter.exactInputSingle.selector,
params
)
);
return bytesToUint(amountBytes);
}
function bytesToUint(bytes memory _bytes) internal pure returns (uint256 value) {
assembly {
value := mload(add(_bytes, 0x20))
}
}
}
deploy-test.js
const hre = require('hardhat');
const ethers = hre.ethers;
const { abi: abiERC20 } = require("../artifacts/contracts/IERC20.sol/IERC20.json");
const uniswapRouter = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"; //ROUTER 02
const uniswapFactory = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; //FACTORY
const wmatic = "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889"; //wmatic mumbai
const weth = "0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa"; //weth mumbai
const fee1 = 500;
const signerAddress = "0x1234567890123456789012345678901234567890";//this must be one of your address with wmatic tokens (I tested on mumbai)
async function main() {
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [signerAddress],
});
const signer = await ethers.provider.getSigner(signerAddress);
var wmaticContract = new ethers.Contract(
wmatic,
abiERC20,
signer
);
var wethContract = new ethers.Contract(
weth,
abiERC20,
signer
);
const TestSwap = await ethers.getContractFactory("TestSwap");
const testSwap = await TestSwap.deploy(
uniswapRouter
);
await testSwap.deployed();
console.log((await wmaticContract.balanceOf(signer._address)).toString());
console.log((await wethContract.balanceOf(signer._address)).toString());
console.log((await wmaticContract.balanceOf(testSwap.address)).toString());
console.log((await wethContract.balanceOf(testSwap.address)).toString());
const amountApprove = ethers.utils.parseEther('1');
const amount = ethers.utils.parseEther('0.5');
const GAS_PARAMS = {
gasLimit: "1250000",//exagerate amount of gas, must be adjusted
gasPrice: ethers.utils.parseUnits('100','gwei').toString(),
};
const txApproveWMatic = await wmaticContract.connect(signer).approve(
testSwap.address,
amountApprove,
GAS_PARAMS);
await txApproveWMatic.wait();
const tx = await testSwap.connect(signer).swapUniswap(
wmatic,
weth,
amount,
fee1,
GAS_PARAMS
);
console.log(tx);
const txResponse = await tx.wait();
console.log(txResponse);
console.log((await wmaticContract.balanceOf(signer._address)).toString());
console.log((await wethContract.balanceOf(signer._address)).toString());
console.log((await wmaticContract.balanceOf(testSwap.address)).toString());
console.log((await wethContract.balanceOf(testSwap.address)).toString());
}
main();
To run it:
$ npx hardhat run scripts/deploy-test.js

Related

Hardhat test issue. Solidity contract mistake?

I am new to crypto and just exploring Solidity language. I try to make a simple Solidify token contract with some basic functionality. It should transfer the token and update the balance. However when I run the test that supposed to try add to balance functionality, I get this error:
npx hardhat test
No need to generate any newer typings.
MyERC20Contract
when I transfer 10 tokens
1) sould transfer tokens correctly
0 passing (728ms)
1 failing
1) MyERC20Contract
when I transfer 10 tokens
sould transfer tokens correctly:
Error: VM Exception while processing transaction: reverted with reason string 'ERC20: transfer amount exceeds balance'
at ERC20._transfer (contracts/ERC20.sol:49)
at ERC20.transfer (contracts/ERC20.sol:25)
at async HardhatNode._mineBlockWithPendingTxs (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1773:23)
at async HardhatNode.mineBlock (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:466:16)
at async EthModule._sendTransactionAndReturnHash (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1504:18)
at async HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:118:18)
at async EthersProviderWrapper.send (node_modules/#nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
Do I make some mistake I'm not aware of?
My test file:
import { SignerWithAddress } from "#nomiclabs/hardhat-ethers/signers";
import { expect } from "chai";
import { ethers } from "hardhat";
import { ERC20 } from "../typechain";
describe("MyERC20Contract", function() {
let MyERC20Contract: ERC20;
let someAddress: SignerWithAddress;
let someOtherAddress: SignerWithAddress;
beforeEach(async function() {
const ERC20ContractFactory = await ethers.getContractFactory("ERC20");
MyERC20Contract = await ERC20ContractFactory.deploy("Hello","SYM");
await MyERC20Contract.deployed();
someAddress = (await ethers.getSigners())[1];
someOtherAddress = (await ethers.getSigners())[2];
});
describe("When I have 10 tokens", function() {
beforeEach(async function() {
await MyERC20Contract.transfer(someAddress.address, 10);
});
});
describe("when I transfer 10 tokens", function() {
it("sould transfer tokens correctly", async function() {
await MyERC20Contract
.connect(someAddress)
.transfer(someOtherAddress.address, 10);
expect(
await MyERC20Contract.balanceOf(someOtherAddress.address)
).to.equal(10);
});
});
});
Mys .sol contract:
//SPDX-License-Identifier: Unlicense: MIT
pragma solidity ^0.8.0;
contract ERC20 {
uint256 public totalSupply;
string public name;
string public symbol;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
_mint(msg.sender, 100e18);
}
function decimals() external pure returns (uint8) {
return 18;
}
function transfer(address recipient, uint256 amount) external returns (bool) {
return _transfer(msg.sender, recipient, amount);
}
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) {
uint256 currentAllowance = allowance[sender][msg.sender];
require(currentAllowance >= amount, "ERC20: Transfer amount exceeds allowance" ) ;
allowance[sender][msg.sender] = currentAllowance - amount;
return _transfer(sender, recipient, amount);
}
function approve(address spender, uint256 amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
return true;
}
function _transfer(address sender, address recipient, uint256 amount) private returns (bool) {
require(recipient != address(0), "ERC20: transfer to zero address");
uint256 senderBalance = balanceOf[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
balanceOf[sender] = senderBalance - amount;
balanceOf[recipient] += amount;
return true;
}
function _mint(address to, uint256 amount) internal {
require(recipient != address(0), "ERC20: transfer to zero address");
totalSupply += amount;
balanceOf[to] +=amount;
}
}
MyERC20Contract = await ERC20ContractFactory.deploy("Hello","SYM");
Since your snippet doesn't specify from which address is the deploying tranaction, the contract is deployed from the first address (index 0).
The 0th address receives the tokens from the constructor, other addresses don't have any tokens.
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
_mint(msg.sender, 100e18);
}
But then your snippet tries to send tokens from the 2nd address (index 1).
someAddress = (await ethers.getSigners())[1];
it("sould transfer tokens correctly", async function() {
await MyERC20Contract
.connect(someAddress)
.transfer(someOtherAddress.address, 10);
Because the someAddress does not own any tokens, the transaction fails.
Solution: Either fund the someAddress in your Solidity code as well, or send the tokens from the deployer address (currently the only address that has non-zero token balance).
Edit:
There is a beforeEach() in your When I have 10 tokens block, but that's applied only to this specific block - not to the when I transfer 10 tokens block that performs the failed transfer.
So another solution is to move this specific beforeEach() to the when I transfer block but, based on the context, it doesn't seem like a very clean approach. A good practice is to have as few as possible test cases not affecting each other.

Adding Liquidity to Pancakeswap in Testnet

I need help with my code. I want to create a simple Smart Contract with adding Liquidity to Pancakeswap. I tried many different things, but the transaction always fails.
I Deployed the Conract,
added BNB to this Contract
and then i want to call the addInitialLiquidity function to set the Liquiditypool.
This is my Errorcode:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "code": 3, "message": "execution reverted: TransferHelper: TRANSFER_FROM_FAILED", "data": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000245472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c454400000000000000000000000000000000000000000000000000000000" }
And this is the Smart Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol";
import "https://github.com/Uniswap/v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol";
import "https://github.com/Uniswap/v2-core/blob/master/contracts/interfaces/IUniswapV2Factory.sol";
contract CWCoin is ERC20, Ownable{
using SafeMath for uint256;
uint8 liquiFee = 1;
IUniswapV2Router02 public uniswapV2Router;
address public uniswapV2Pair;
bool initialLiqDone = false;
constructor ()
ERC20("CWCoin", "CWC"){
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(
0xD99D1c33F9fC3444f8101754aBC46c52416550D1
);
address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
uniswapV2Router = _uniswapV2Router;
uniswapV2Pair = _uniswapV2Pair;
_mint(msg.sender, 1000000 * 10 ** uint(decimals()) );
_mint(address(this), 100000 * 10 ** uint(decimals()) );
}
receive() external payable{}
function swapAndLiquify(uint256 tokens) private {
// split the contract balance into halves
uint256 half = tokens.div(2);
uint256 otherHalf = tokens.sub(half);
uint256 initialBalance = address(this).balance;
// swap tokens for ETH
swapTokensForEth(half); // <- this breaks the ETH -> HATE swap when swap+liquify is triggered
// how much ETH did we just swap into?
uint256 newBalance = address(this).balance.sub(initialBalance);
// add liquidity to uniswap
addLiquidity(otherHalf, newBalance);
}
function addInitialLiquidity() public onlyOwner{
// approve token transfer to cover all possible scenarios
_approve(address(this), address(uniswapV2Router), ~uint256(0));
_approve(address(this), address(uniswapV2Pair), ~uint256(0));
// add the liquidity
uniswapV2Router.addLiquidityETH{value: address(this).balance}(
address(this),
balanceOf(address(this)),
0, // slippage is unavoidable
0, // slippage is unavoidable
owner(),
block.timestamp
);
initialLiqDone = true;
}
function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
// approve token transfer to cover all possible scenarios
_approve(address(this), address(uniswapV2Router), tokenAmount);
// add the liquidity
uniswapV2Router.addLiquidityETH{value: ethAmount}(
address(this),
tokenAmount,
0, // slippage is unavoidable
0, // slippage is unavoidable
address(0),
block.timestamp
);
}
function swapTokensForEth(uint256 tokenAmount) private {
// generate the uniswap pair path of token -> weth
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
_approve(address(this), address(uniswapV2Router), tokenAmount);
// make the swap
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0, // accept any amount of ETH
path,
address(this),
block.timestamp
);
}
function _transfer(
address from,
address to,
uint256 amount
) internal override{
require(from != address(0), "From not null address");
require(to != address(0), "To not null address");
if(amount == 0){
super._transfer(from, to, 0);
return;
}
uint256 liqui = amount.mul(liquiFee).div(100);
swapAndLiquify(liqui);
super._transfer(from, to, amount.sub(liqui));
}
}
Smart Contract in Testnet
0xF0e54bA09c3e7E66f414dCE375f5FAE6846041F7
Transaction
0xa80e9acbf7310de437f41afdf19f9554bdd846c37ad004dc8efbec9c29093cb2
I hope anyone can help.
Thank you very much
Edit:
I tried many different things.
Approved the Router,
Approved the Pair,
Approved my wallet Address
I tried to add Liquidity via bscscan. Nothing worked.
The exception is originating from IUniswapV2Router02 contract, in safeTransferFrom function of TransferHelper library. This function wants to transfer your tokens to pair contract by calling transferFrom function of your contract. Pancakeswap will assume the transfer succeeded if you return true in the transferFrom function. I checked your contract on bscscan testnet but it's not verified and so I couldn't read what transferFrom function is doing. I'm guessing it's calling _transfer but then not returning true when it's done.

Smart Contract Withdrawal from contract owner

For example I don't want to store ETH on Smart Contract but to the contract owner. Then how to implement withdrawal from the contract owner?
pragma solidity ^0.8.7;
contract WDfromContractOwner {
address public owner;
constructor() {
owner=msg.sender;
}
function deposit() external payable returns (bool) {
payable(owner).transfer(msg.value);
return true;
}
function withdrawal() external returns (bool) {
// Witdrawal from owner address....???
return true;
}
}
A smart contract is not able to pull ETH from an address (other than the address sending the ETH to the contract). The transfer needs to always be originated from and signed by the sender (in your case the owner).
However, it can pull tokens owned by an address. The sender (owner) needs to approve() the amount at first, interacting with the token contract from their address. Then your contract can invoke the token's transferFrom() function.
pragma solidity ^0.8;
interface IERC20 {
function transferFrom(address, address, uint256) external returns (bool);
}
contract WDfromContractOwner {
address public owner;
function withdrawToken() external {
// Only reachable from the mainnet.
// Transfers from other networks (such as Remix VM) will fail.
address mainnetUSDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address receiver = msg.sender; // address of the user executing the `withdrawToken()`
uint256 amount = 5 * 1e6; // 5 USDT, 6 decimals
require(
// the `owner` needs to execute `approve()` on the token contract directly from the `owner` address
// so that the `WDfromContractOwner` contract can spend their tokens
IERC20(mainnetUSDT).transferFrom(owner, receiver, amount)
);
}
}
You can get the approved amount using web3.js:
const USDTAddress = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
const ownerAddress = "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF";
// just the `balanceOf()` is sufficient in this case
const ABI = [
{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}
];
const USDTContract = new web3.eth.Contract(ABI, USDTAddress);
const approved = await USDTContract.methods.balanceOf(ownerAddress).call();
console.log(approved);
If you are already are transferring the funds to the owner each time an user deposit it should not be necessary, but if you want you could do it anyway, you have different options like passing the amount as a parameter, have a default or a minimum amount, etc, but for simplicity to withdraw all the funds just add this two lines in the function
(bool result,)= payable(owner).call{value: address(this).balance }("");
return result

Testing a Payable Function in Solidity

So I'm trying to test a payable function on the following smart contract here using the truffle framework:
contract FundMe {
using SafeMathChainlink for uint256;
mapping(address => uint256) public addressToAmountFunded;
address[] public funders;
address public owner;
AggregatorV3Interface public priceFeed;
constructor(address _priceFeed) public {
priceFeed = AggregatorV3Interface(_priceFeed);
owner = msg.sender;
}
function fund() public payable {
uint256 mimimumUSD = 50 * 10**18;
require(
getConversionRate(msg.value) >= mimimumUSD,
"You need to spend more ETH!"
);
addressToAmountFunded[msg.sender] += msg.value;
funders.push(msg.sender);
}
I specifically want to test the payable function, and I've seen a few things on the internet where people create other contracts with initial balances and then send their testing contract some eth. But I would just like to grab a local ganache wallet and send some eth to the contract and then test that, if someone could show me some test javascript code to wrap my head around this that would be much appreciated!
For a contract to be able to receive ETH (or any native token - BNB on Binance Smart Chain, TRX on Tron network, ...) without invoking any function, you need to define at least one of these functions receive() (docs) or fallback() (docs).
contract FundMe {
// intentionally missing the `function` keyword
receive() external payable {
// can be empty
}
// ... rest of your code
}
Then you can send a regular transaction to the contract address in truffle (docs):
const instance = await MyContract.at(contractAddress);
await instance.send(web3.toWei(1, "ether"));
Note that because receive() and fallback() are not regular functions, you cannot invoke them using the truffle autogenerated methods: myContract.functionName()
If you want to execute a payable function sending it ETH, you can use the transaction params (docs). It's always the last argument, after all of the regular function arguments.
const instance = await MyContract.at(contractAddress);
await instance.fund({
value: web3.toWei(1, "ether")
});
Note: If the fund() function had 1 argument (let's say a bool), the transaction params would be the 2nd:
await instance.fund(true, {
value: web3.toWei(1, "ether")
});

How to add method id in metamask

I have deployed smart contract using remix IDE, launched with Injected Web3 on Ropsten test network. I could call BuyTokens function within solidity IDE successfully, but when tried to buy tokens with metamask from other address transaction get reverted. I can see the difference between those operations on ropsten.etherscan explorer - the difference is in Input Data field.
Metamask transaction has value 0x and transaction via remix is:
Function: buyTokens() ***
MethodID: 0xd0febe4c
Code:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Token {
// Track how many tokens are owned by each address.
mapping (address => uint256) public balanceOf;
// Modify this section
string public name = "DemoCoin";
string public symbol = "DC";
uint8 public decimals = 8;
uint256 public totalSupply = 1000000000 * (uint256(10) ** decimals);
address public owner;
//uint scaler = 10e18; // == 1 ETH in wei
//uint public coinPrice = 20; //initial price => 20 cents
event Transfer(address indexed from, address indexed to, uint256 value);
constructor() {
// Initially assign all tokens to the contract's creator.
owner = msg.sender;
balanceOf[msg.sender] = totalSupply;
emit Transfer(address(0), msg.sender, totalSupply);
}
// Might be executed automaticlly
// https://blog.chronologic.network/schedule-your-transaction-now-using-mycrypto-and-myetherwallet-17b48166b412
// function changeCoinPrice() public {
// uint newCoinPrice;
// require(msg.sender == address(0));
// coinPrice = newCoinPrice;
// }
function buyTokens() public payable {
// msg.value in wei so 1ETH = 10e18
// lets set 0.20 cents for 1 token
uint paidAmount;
require(balanceOf[msg.sender] >= paidAmount);
require(balanceOf[owner] >= value);
uint tokens;
tokens = value/10e14;
balanceOf[owner] -= tokens;
balanceOf[msg.sender] += tokens;
emit Transfer(owner, msg.sender, tokens);
}
function msgSenderBalancce() public view returns (uint) {
return balanceOf[msg.sender];
}
function withDrawEth() public view {
require(msg.sender == owner);
}
}
Why these methods are called diffrently? And how to add method id in metamask? Or am I missing something and this should be handled in other way?
MetaMask has a very basic UI. It only allows transfers of ETH and standardized tokens, but it doesn't show any buttons to call other contract functions. It also doesn't allow creating any custom buttons in their UI.
You'll need to set the data field of the transaction to 0xd0febe4c (which effectively executes the buyTokens() function).
But - they also don't allow specifying the data field value manually in the UI, so you'll need to preset it using the Ethereum provider API.
Your web app connects to the user's MetaMask acccount. It opens a MetaMask window and the user needs to manually confirm the connect.
The web app sends a request to MetaMask specifying the transaction with data field value.
The user confirms the transaction (which now includes the data field value 0xd0febe4c) in their MetaMask UI.