Calling a solidity payable function with etherjs - solidity

I have a basic Solidity smart contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TestContract {
uint256 public _blockTimestamp;
function accumulated() public payable returns (uint256) {
_blockTimestamp = block.timestamp;
return 1;
}
}
And using remix IDE I can compile it and check the value of _blockTimestamp changing after executing the accumulated function.
Now, I can deploy the contract and check the value of the public variable without any problem with etherjs:
const provider = new providers.JsonRpcProvider(getEnv('RINKEBY_NODE_URL'));
const wallet = new Wallet(getEnv('ROPSTEN_PRIVATE_KEY'), provider);
const TestContract = TestContract__factory.connect(getEnv('TEST_CONTRACT'), provider);
const _blockTimestamp = await NFTLTokenContract._blockTimestamp();
The problem is when I try to execute the function accumulated. Being a payable function I need a signer:
const provider = new providers.JsonRpcProvider(getEnv('RINKEBY_NODE_URL'));
const wallet = new Wallet(getEnv('ROPSTEN_PRIVATE_KEY'), provider);
const TestContract = TestContract__factory.connect(getEnv('TEST_CONTRACT'), provider);
const _blockTimestamp = await TestContract._blockTimestamp();
const accumulated = await TestContract.accumulated('1', wallet);
But I still get the error:
Error: sending a transaction requires a signer
(operation="sendTransaction", code=UNSUPPORTED_OPERATION,
version=contracts/5.5.0)
What am I missing?

You are trying to call a non-view function by using only a provider, you must provide a signer in order to call the function.
Try connecting to the contract using the wallet as the signer:
const TestContract = TestContract__factory.connect(getEnv('TEST_CONTRACT'), wallet);

Related

webjs execution reverting when calling deployed contract: var err = new Error('Returned error: ' + message)

I'm running the following javascript file and using web3js to call a smart contract (0xF3885ca057a42B10b6cb432B816FE11426a2E369) on Goerli:
const Web3 = require("web3");
// Loading the contract ABI
// (the results of a previous compilation step)
const fs = require("fs");
const { abi } = JSON.parse(fs.readFileSync("EtherSplitter.json"));
async function main() {
// Configuring the connection to an Ethereum node
const network = process.env.ETHEREUM_NETWORK;
const web3 = new Web3(
new Web3.providers.HttpProvider(
`https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
)
);
// Creating a signing account from a private key
const signer = web3.eth.accounts.privateKeyToAccount(
process.env.SIGNER_PRIVATE_KEY
);
web3.eth.accounts.wallet.add(signer);
// Creating a Contract instance
const contract = new web3.eth.Contract(
abi,
// Replace this with the address of your deployed contract
process.env.ETHERSPLITTER_CONTRACT
);
// Issuing a transaction that calls the splitEther method
const tx = contract.methods.splitEther(["0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc"]);
const receipt = await tx
.send({
from: signer.address,
value: 1e15, // IS THIS CORRECT? IF NOT, HOW DO I SPECIFY VALUE FOR SEND
gas: await tx.estimateGas(),
})
.once("transactionHash", (txhash) => {
console.log(`Mining transaction ...`);
console.log(`https://${network}.etherscan.io/tx/${txhash}`);
});
// The transaction is now on chain!
console.log(`Mined in block ${receipt.blockNumber}`);
}
require("dotenv").config();
main();
The smart contract is:
contract EtherSplitter {
function splitEther(address payable[] memory recipients) public payable {
uint fee = 10;
recipients[0].transfer(msg.value * fee / 100);
recipients[1].transfer(msg.value * (100 - fee) / 100);
}
receive() external payable {
}
}
Execution is reverting with the following error:
users/myusername/demo-eth-tx/node_modules/web3-core-helpers/lib/errors.js:28
var err = new Error('Returned error: ' + message);
I think I'm using send incorrectly, and incorrectly specifying the send value. How do I fix that?
Based on your code, seems like you mixed up some ether.js into your web3.js code coz in web3.js there when executing contract because in web3.js, function parameters doesn't need to be in an array like in ether.js
Try this
const tx = contract.methods.splitEther("0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc");

Unable to require ERC-20 tokens in a Solidity function

I have a basic ERC-20 Token defined as
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor() ERC20("Token", "TOKEN") {}
function mint(address account, uint256 amount) public {
_mint(account, amount);
}
}
I have another contract Item that has a method I want to cost 1 Token, basing answer off https://ethereum.stackexchange.com/a/78911/30804
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
contract Item {
IERC20 private token;
constructor(address tokenAddress) {
token = IERC20(tokenAddress);
}
function myMethod() public {
bool success = token.transferFrom(msg.sender, address(this), 1 ether); // also tried just 1
require(success, "Insufficient Funds: Requires 1 Token");
// do things
}
}
I'm running this inside a Hardhat test
const TokenFactory = await ethers.getContractFactory("Token");
Token = await Token.deploy();
await Token.mint(owner.address, ethers.utils.parseUnits("1", 18));
await Token.approve(owner.address, ethers.utils.parseUnits("1", 18));
const ItemFactory = await ethers.getContractFactory("Item");
Item = await ItemFactory.deploy(Token.address);
await Item.myMethod(); // this is the line that errors
Everything runs and I can see debug code from the solidity contracts, but I keep getting an error that
reverted with reason string 'ERC20: insufficient allowance'
that I traced back to the openzeppelin internal function _spendAllowance
After some debugging I thought that the culprit was because I needed to approve, so I added a call to approve but I'm still getting the same error
I'm assuming my issue is something basic can anyone see what it might be? Thanks in advance.
await Token.approve(owner.address, ethers.utils.parseUnits("1", 18));
You're giving the approval to the owner address, but the actual msg.sender inside the transferFrom() function is the Item address (as the caller of the function is the Item contract).
Solution: Approve the Item address as the spender.
// after the `Item` contract has been deployed
await Token.approve(Item.address, ethers.utils.parseUnits("1", 18));
await Item.myMethod();

Can't transfer Matic to smart contract

I'm trying to transfer Matic to my smart contract in the Mumbai test net using ethers.
I'm using the most basic contract which comes with hardhat - Greeter. sol.
The error I keep getting is(in the polygonscan-mumbai):
The client side transfer using ethers:
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const erc20Contract = new ethers.Contract("0x0000000000000000000000000000000000001010", erc20abi, signer);
const parsedAmount = ethers.utils.parseUnits(amount.toString(), 'ether');
const transferTokens = await erc20Contract.transfer(contractAddress , parsedAmount);
Greeter.sol:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract Greeter {
string private greeting;
constructor(string memory _greeting) {
console.log("Deploying a Greeter with greeting:", _greeting);
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
greeting = _greeting;
}
}
Also when I manually try to send Matic to the smart contract using metamsk it's giving me the same error(only to contracts, not other wallets).
But if I try other tokens it works fine - am I missing something?
Your contract needs to implement either receive() or fallback() function to be able to accept native currency of the network.
Docs: https://docs.soliditylang.org/en/v0.8.13/contracts.html#special-functions
Example:
contract Greeter {
// ...
receive() external payable {
}
}

Upgreadable ERC20 TypeError: Cannot create property 'kind' on string

I created 2 smart contracts.
contract A is ERC20 token and B is a contract that accepts ERC20 A as payment method. When deploying, contract A got deployed but when I passed its proxy address to the initialize function in contract B for deployment it shows this error:
TypeError: Cannot create property 'kind' on string '0x814bd9012bD1e51b86890343b9731501875502e8'
what could be the problem?
hardhat deploy script
const token = await ethers.getContractFactory("Token");
console.log("Deploying token...");
const tokeninit= await upgrades.deployProxy(token , {
initializer: "initialize",
});
await tokeninit.deployed();
const tokenaddr = tokeninit.address;
console.log("token deployed at :", tokenaddr );
const SmartB= await ethers.getContractFactory("SmartB");
const SmartBInit= await upgrades.deployProxy(SmartB,tokenaddr, {
initializer: "initialize",
});
Smart contract B shorten code:
contract SamrtB is Initializable, UUPSUpgradeable, OwnableUpgradeable {
using CountersUpgradeable for CountersUpgradeable.Counter;
CountersUpgradeable.Counter private _tokenIdCounter;
IERC20Upgradeable public tokenAccepted;
constructor() initializer {}
function initialize(address _token) initializer public {
__Ownable_init();
__UUPSUpgradeable_init();
tokenAccepted =IERC20Upgradeable(_token);
}
I was passing the parameters in the next smart contract the wrong way, it should be
const SmartBInit= await upgrades.deployProxy(SmartB,[tokenaddr],{}
Instead of
const SmartBInit= await upgrades.deployProxy(SmartB,tokenaddr, {}

How to deploy solidity smart contract when one contract's constructor depends on another contract?

The code example is https://github.com/facuspagnuolo/ethereum-spiking/tree/master/5-token-sale-contract
The related files are:
1. contracts\MyToken.sol
contract MyToken is BasicToken, Ownable {
uint256 public constant INITIAL_SUPPLY = 10000;
function MyToken() {
totalSupply = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
Transfer(0x0, msg.sender, INITIAL_SUPPLY);
}
}
2. contracts\TokenSale.sol
contract TokenSale is Ownable {
MyToken public token;
uint256 public priceInWei;
bool public tokenSaleClosed;
event TokenPurchase(address buyer, address seller, uint256 price, uint256 amount);
function TokenSale(MyToken _token, uint256 _price) public {
if (_price < 0) return;
token = _token;
priceInWei = _price;
tokenSaleClosed = false;
}
}
3. migrations\2_deploy_contracts.js
const MyToken = artifacts.require("./MyToken.sol");
const TokenSale = artifacts.require("./TokenSale.sol");
module.exports = function(deployer) {
deployer.deploy(MyToken);
deployer.deploy(TokenSale);
};
when I deploy it by truffle and testrpc ($ truffle migrate), it fails as the following:
Using network 'development'.
Running migration: 2_deploy_contracts.js
Deploying MyToken...
... 0x289577d078c8fbc61585127ac123dbef43aa711529bf079c4fd400206c65e0de
MyToken: 0x33ddda65330e75e45d3d2e4e270457915883c2fc
Deploying TokenSale...
Error encountered, bailing. Network state unknown. Review successful transactions manually.
Error: TokenSale contract constructor expected 2 arguments, received 0
at C:\Users\zklin\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-contract\contract.js:390:1
at new Promise ()
at C:\Users\zklin\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-contract\contract.js:374:1
at
at process._tickCallback (internal/process/next_tick.js:188:7)
http://truffleframework.com/docs/getting_started/migrations#deployer
// Deploy A, then deploy B, passing in A's newly deployed address
deployer.deploy(A).then(function() {
return deployer.deploy(B, A.address);
});
Might work migrating only the second one so TokenSale and automatically it will be deployed MyToken.