【问题标题】:How to receive and send USDT in a smart contract?如何在智能合约中接收和发送 USDT?
【发布时间】:2021-05-12 22:22:07
【问题描述】:

是否有任何指南或代码可以作为示例来实现智能合约接收和发送 USDT 到其他地址的功能。

感谢您的帮助

【问题讨论】:

    标签: ethereum solidity


    【解决方案1】:

    代币余额存储在代币合约中(在本例中为 USDT),而不是您的。所以发送代币是一个简单的过程——你只需在代币合约上执行正确的功能。请注意,您的合约至少需要保留即将发送的金额,否则交易将恢复。

    pragma solidity ^0.8;
    
    interface IERC20 {
        function transfer(address _to, uint256 _value) external returns (bool);
        
        // don't need to define other functions, only using `transfer()` in this case
    }
    
    contract MyContract {
        // Do not use in production
        // This function can be executed by anyone
        function sendUSDT(address _to, uint256 _amount) external {
             // This is the mainnet USDT contract address
             // Using on other networks (rinkeby, local, ...) would fail
             //  - there's no contract on this address on other networks
            IERC20 usdt = IERC20(address(0xdAC17F958D2ee523a2206206994597C13D831ec7));
            
            // transfers USDT that belong to your contract to the specified address
            usdt.transfer(_to, _amount);
        }
    }
    

    但是由于余额存储在外部合约中,您不能只通过执行合约中的函数来让用户向您发送代币。请参阅我的other answer,它展示了一个示例,如果可能的话,它是如何被滥用的(只需将approve 替换为transfer,但逻辑是相同的)。

    一些代币标准(例如ERC-1155ERC-721)允许在您的合约收到代币时向您的合约发送挂钩。挂钩函数名称和所需参数在链接文档中。但是代币合约是否给你发送了一个钩子,这取决于

    • 代币合约的实现(特别是 USDT 没有实现)
    • 您的合约(您必须为您想要接收的所有代币标准实现挂钩功能 - 或者至少是通用的fallback(),这在某些情况下可以使用)
    • 有时也会在发件人身上。

    您可以要求您的用户批准一些USDT通过您的地址使用,然后您的合约可以执行USDT合约的transferFrom()功能(其中“from”是批准您使用他们的代币的用户)。但是,正如链接的其他答案所暗示的那样,需要在您的合同之外进行批准。

    您还可以拥有一个链下应用程序来侦听令牌合约发出的事件日志(在您的情况下,USDT 合约上的 Transfer() 事件)。事件日志包含转账信息,包括接收方和金额。因此,您的(链下)应用程序只能过滤您的地址是接收者的事件,并在处理事件日志时执行一些操作。

    【讨论】:

    • 嗨,彼得,感谢您的帮助。尝试执行代码时,出现错误,如下所示:“ParserError:只有状态变量或文件级变量可以有文档字符串。”关于变量“usdt”的这个错误
    • 哦,我使用了多行注释块来拆分注释,以便在默认情况下不检查文档块的 IDE(Remix)中获得更好的可读性。如果您删除评论,错误将消失。
    • 嗨 Petr,但是如果我评论错误行,问题就会通过,但是我可以通过什么方式发送资金
    • 我的意思是删除以 /** 开头并以 */ 结尾的多行注释 - 或者像我在问题中所做的那样用单行 cmets 替换它。
    • @NikolaLukic 测试网上没有正式的 USDT 合约,所以请记住,您需要使用部署在不同地址的合约副本。
    【解决方案2】:

    当我使用上面的代码时,我得到了一个错误

    错误:事务已恢复:无法识别功能选择器并且没有后备功能

    我不知道为什么

    pragma solidity ^0.8.0;
    
    import "hardhat/console.sol";
    
    interface IERC20 {
        function transfer(address _to, uint256 _value) external returns (bool);
    }
    
    contract Greeter {
    
      string greeting;
    
      constructor(string memory _greeting) {
        console.log("Deploying a Greeter with greeting:", _greeting);
        greeting = _greeting;
      }
    
      function sendUSDT(address _to, uint256 _amount) external {
             // This is the mainnet USDT contract address
             // Using on other networks (rinkeby, local, ...) would fail
             //  - there's no contract on this address on other networks
        IERC20 usdt = IERC20(address(0x5FbDB2315678afecb367f032d93F642f64180aa3));
            
            // transfers USDT that belong to your contract to the specified address
        usdt.transfer(_to, _amount);
      }
    }
    

    我将 USDT(TetherToken.sol) 部署到我的以太坊开发节点。

    const TetherToken = artifacts.require("TetherToken"); 
    
    contract('TetherToken',accounts => {
        before(async () => {
            let tetherToken = await TetherToken.at("0x5FbDB2315678afecb367f032d93F642f64180aa3");
            //this address is the same as signers[1].address in hardhat
            tetherToken.transfer("0x70997970c51812dc3a010c7d01b50e0d17dc79c8", web3.utils.toBN("1000000000"));
            let b = await tetherToken.balanceOf("0x70997970c51812dc3a010c7d01b50e0d17dc79c8")
            console.log(b.toString());
        });
    
    });
    

    transfer 方法在 truffle 测试中效果很好, 但是当用安全帽测试合约时,它失败了。

    const { ethers, upgrades } = require("hardhat");
    
    async function main() {
    
      const signers = await ethers.getSigners();
    
      const Greeter = await hre.ethers.getContractFactory("Greeter");
      const greeter = await Greeter.deploy("Hello, Hardhat!");
    
      await greeter.deployed();
    
      let overrides = {
    
        // The maximum units of gas for the transaction to use
        gasLimit: 2100000,
    
        // The price (in wei) per unit of gas
        gasPrice: ethers.utils.parseUnits('8.0', 'gwei')
    
      };
    
      await greeter.connect(signers[1]).sendUSDT(signers[2].address, ethers.utils.parseUnits('100.00', 'mwei'), overrides);
    }
    
    // We recommend this pattern to be able to use async/await everywhere
    // and properly handle errors.
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error);
        process.exit(1);
      });
    

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 2022-08-12
      • 2022-06-14
      • 2021-12-17
      • 2018-07-18
      • 1970-01-01
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      相关资源
      最近更新 更多