1

我在 Solidity 中编写了一份合同,并考虑了以下任务:

  • 用户批准智能合约从他们的钱包中转移一定数量的代币。

  • 智能合约使用此金额转移到作为参数给出的地址。但它也需要从这个数量中提取 1 个代币才能转移给合约的开发者。

  • 如果一切成功,用户会收到“支付成功!” 信息。

第一步(批准)是使用 React 和 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);
    };



一旦批准成功,函数的第二部分就解决了。我部署的合约有一个名为send_usdt. 通过这个功能,我的智能合约能够转移批准的金额。

/ 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!";  
    }
}

一旦 React 中函数的第二部分解析完成,我就会收到“付款成功!”的确认信息。但是代币没有被转移。我在“From Wallet”、“To Wallet”和“Deploy Wallet”中保留了与以前相同的金额。


问题出在反应片段中。通过改变方法callsell钱可以成功转移。

const response = await contract.methods.send_usdt
(
    '0xToAddress',
    web3.utils.toHex(3e18)
)
.call({ from: '0xFromAddress' });

改为:

const response = await contract.methods.send_usdt
(
    '0xToAddress',
    web3.utils.toHex(3e18),
    { from: '0xFromAddress' }
)
.send();

这有效,但提出了另一个问题。当我使用前面的call方法时,函数返回“支付成功!” 并使用 sell 方法收到一个对象。

由于“付款成功”不是真的,我想知道当有人使用 call 方法与我的合约交互时是否可以抛出异常。

那可能吗?

4

1 回答 1

0

按照@Kuly14 的回答,为了更清楚,您可能需要创建以下函数:

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");

    usdt.transferFrom(msg.sender, owner, 1);
    usdt.transferFrom(msg.sender, _to, _amount-1);

    return "Payment successful!";  
}

笔记:

  1. 只需调用该transferFrom方法,如果出现问题,它将跳转相应的错误。你不需要处理它们。
  2. 我更改了您转移代币的顺序。首先,我将它们发送给所有者,然后发送给所需的收件人以避免费用支付问题,但如果您更喜欢相反的方式,这是可能的。
于 2022-02-04T23:25:29.130 回答