Solidity

失敗並出現錯誤“TransferHelper:TRANSFER_FROM_FAILED”,所有氣體都用完了

  • August 3, 2021

我試圖在 Uniswap 主網上用 USDT 購買一些CHY 失敗了,error 'TransferHelper: TRANSFER_FROM_FAILED'

這是我失敗的tx 連結

這是來自其他人的成功tx 連結。

我注意到我的交易費異常,比其他成功的交易高得多,而且無論我怎麼提高gasLimit,它總是用完,只需要更多的時間。

tx 成功的頁面有Uniswap V2: CHY-USDT,我的程式碼中沒有用到,這就是我的 tx 從來沒有找到正確的方式,但總是不斷尋找並吃光所有 gas 的原因嗎?

如何更正程式碼?

更新 1:在交易前添加“approve()”。“approve()”第一次成功,之後就再也沒有成功,總是這樣失敗

const CHY = new Token(ChainId.MAINNET, '0x35A23BC27c345b36DeE700a256F69C6334030971', 9)
const USDT = new Token(ChainId.MAINNET, '0xdAC17F958D2ee523a2206206994597C13D831ec7', 6)

const pair = await Fetcher.fetchPairData(CHY, USDT)

const route = new Route([pair], USDT) // direction, from USDT -> CHY

var base = ethers.BigNumber.from(10).pow(route.path[0].decimals)
var amountIn = ethers.BigNumber.from(50).mul(base) // 50 * 10^6 == 50 USDT
console.log(amountIn.toString()) // 50 USDT

const trade = new Trade(
   route, 
   new TokenAmount(USDT, amountIn),
   TradeType.EXACT_INPUT) 


const slippageTolerance = new Percent('50', '10000') // 0.5%
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw
const path = [USDT.address, CHY.address] // <---------check direction
const to = MY_WALLET;
const deadline = Math.floor(Date.now() / 1000) + 20*60 // 20 minutes

const provider = ethers.getDefaultProvider('mainnet', {
   infura: INFURA_ID
})

const signer = new ethers.Wallet(MY_WALLET_PRIVATE_KEY)
const account = signer.connect(provider)
const uniswap = new ethers.Contract(
   '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', // fixed Route02.addr
   ['function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'],
   account
)

// approve
const contract_usdt = new ethers.Contract(
   addr_usdt,
   //['function approve(address spender, uint value) public'],
   ['function approve(address spender, uint amount) public returns(bool)'],
   account
);
const tx_approve = await contract_usdt.approve(uniswap.address, amountIn, {
   gasPrice: gasPrice,
   gasLimit: gasLimit
})

console.log('tx_approve: ' + tx_approve.hash);

const receipt_approve = await tx_approve.wait()
console.log(receipt_approve)


const tx = await uniswap.swapExactTokensForTokens(
   amountIn.toString(),
   amountOutMin.toString(),
   path,
   to,
   deadline,
   { 
       gasLimit: 400000,
       gasPrice: ethers.utils.parseUnits("40", "gwei") 
   }
)
console.log(`Transaction hash: ${tx.hash}`)
const receipt = await tx.wait()

我試過了path=[USDT, UNIWAP_V2_CHY_USDT, CHY]也失敗了

在嘗試交換之前,您沒有批准 USDT 到路由器地址。

USDT 合約因未獲得批准而使用assert代替revert或取消交易。throw使用assert將消耗所有剩餘的氣體。Tether 使用 是不好的做法assert,但這可能是因為他們的契約真的很舊。

編輯:此外,USDT 契約要求您在進行另一個批准呼叫之前將津貼​​設置為 0。下面是USDT合約的相關程式碼:

function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {

   // To change the approve amount you first have to reduce the addresses`
   //  allowance to zero by calling `approve(_spender, 0)` if it is not
   //  already 0 to mitigate the race condition described here:
   //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));

   allowed[msg.sender][_spender] = _value;
   Approval(msg.sender, _spender, _value);
}

引用自:https://ethereum.stackexchange.com/questions/103595