I wrote a contract in Solidity with the following task in mind:
The user approves the smart contract to transfer a certain amount of tokens from their wallet.
The smart contract uses this amount to transfer to an address given as a parameter. But it also takes 1 token from this amount to transfer to the developer of the contract.
If everything succeeds, the user receives a "Payment successful!" message.
The first step (the approval) was made using React and Web3:
const derc20contract = '0x36850b80ad73fe66216609B9796ed6ceae8BE29F';
const handleClick = async (e) => {
e.preventDefault();
const prtmp = await detectEthereumProvider();
// -------------------- Approve Part ------------------------------//
const web3 = new Web3(prtmp);
const erc20contract = new web3.eth.Contract(
erc20abi,
derc20token,
{ from: '0xFromAddress' }
);
await erc20contract.methods.approve(derc20contract, web3.utils.toHex(3e18)).send();
// ---------------------------------------------------------------//
const contract = new web3.eth.Contract(derc20abi, derc20contract);
const response = await contract.methods.send_usdt(
'0xToAddress',
web3.utils.toHex(3e18)
)
.call({ from: '0xFromAddress'});
console.log(response);
};
Once the approval succeeds the second part of the function resolves. The contract I deployed has a function called send_usdt
. Through this function is my smart contract able to transfer the amount approved.
/ SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
interface IERC20 {
function transfer(address _to, uint256 _value) external returns(bool);
function transferFrom(address _from, address _to, uint _amount) external returns (bool);
function allowance(address _owner, address _contract) external returns (uint256);
function balanceOf(address _buyer) external view returns (uint256);
function approve(address _contract, uint tokens) external returns (bool);
}
contract DPortalSubscription {
address private owner;
mapping(address => uint32) subscription_fees;
constructor()
{
owner = msg.sender;
}
function check_balance() external view returns (uint256)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
uint256 balance = usdt.balanceOf(msg.sender);
return balance;
}
function check_sender_address() external view returns (address)
{
return msg.sender;
}
function check_allowance()external returns(uint256)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
uint256 allowance = usdt.allowance(msg.sender, address(this));
return allowance;
}
function send_usdt(address _to, uint256 _amount) external returns (string memory)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
require(_amount > 1, "Purchases must be higher than 1 usdt");
require(usdt.balanceOf(msg.sender) >= _amount, "The buyer doesn't have enough funds");
require(usdt.allowance(msg.sender, address(this)) >= _amount, "Permissions to transfer tokens denied");
require(usdt.transferFrom(msg.sender, _to, _amount-1) == true, "Couldn't transfer tokens to seller");
require(usdt.transferFrom(msg.sender, owner, 1) == true, "Couldn't transfer tokens to support");
return "Payment successful!";
}
}
Once the second part of the function in React resolves, I receive the confirmation "Payment successful!" But the tokens weren't transferred. I keep the same amount in my "From Wallet", "To Wallet" and "Deploy Wallet" as before.
The problem was inside the react snippet. By changing the method call
to sell
the money could be successfully transferred.
const response = await contract.methods.send_usdt
(
'0xToAddress',
web3.utils.toHex(3e18)
)
.call({ from: '0xFromAddress' });
was changed to:
const response = await contract.methods.send_usdt
(
'0xToAddress',
web3.utils.toHex(3e18),
{ from: '0xFromAddress' }
)
.send();
which worked but raised another question. When I use the previous call
method, the function returns "Payment Successful!" and with the sell method I receive an Object.
Since "Payment Successful" isn't true, I was wondering if it could be possible to throw an Exception when someone interacts with my contract using the call method.
Is that possible?