Contract-Development
是什麼導致所需的氣體超過限額或總是交易失敗?
這可能看起來重複,但我找不到正確的答案。我的目標是開發一個合約,合約所有者可以設置收件人和他們可以提取的代幣數量。設置完成後,接收者可以呼叫帶有帶有 gas 價格的元遮罩的函式並贖回代幣。
- 已通過 Remix 部署了以下合約(代幣所有者與合約所有者不同)
- 當嘗試執行
setBalances
每個數組中只有 2 個項目的方法時,導致錯誤transact to WithDraw.setBalances errored: Error: gas required exceeds allowance or always failing transaction
- 已將氣體限制更改為
900000000000
但結果仍然相同。- 只是為了檢查,呼叫
redeem
它也會產生相同的錯誤transact to WithDraw.redeem errored: Error: gas required exceeds allowance or always failing transaction
智能合約程式碼
pragma solidity ^0.4.18; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address public owner; event OwnershipTransferred (address indexed _from, address indexed _to); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() public{ owner = msg.sender; OwnershipTransferred(address(0), owner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0)); owner = newOwner; OwnershipTransferred(owner,newOwner); } } /** * @title Token * @dev API interface for interacting with the Token contract */ interface Token { function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); function balanceOf(address _owner) constant external returns (uint256 balance); } contract WithDraw is Ownable { Token token; mapping(address => uint256) public redeemBalanceOf; event BalanceSet(address indexed beneficiary, uint256 value); event Redeemed(address indexed beneficiary, uint256 value); function WithDraw() public { address _tokenAddr = MY_TOKEN_ADDR; token = Token(_tokenAddr); } function setBalances(address[] dests, uint256[] values) onlyOwner public { uint256 i = 0; while (i < dests.length) { if(dests[i] == address(0)) continue; uint256 toSend = values[i] * 10**18; redeemBalanceOf[dests[i]] += toSend; i++; BalanceSet(dests[i],values[i]); } } function redeem(uint256 quantity) external{ uint256 baseUnits = quantity * 10**18; require(redeemBalanceOf[msg.sender]>=baseUnits); redeemBalanceOf[msg.sender] -= baseUnits; token.transferFrom(owner,msg.sender,baseUnits); Redeemed(msg.sender,quantity); } }
錯誤的原因是什麼?合約所有者是否應該與代幣合約所有者相同?
編輯1
根據@smarx 回复,更改瞭
setBalances
如下方法。function setBalances(address[] dests, uint256[] values) onlyOwner public { for (uint256 i = 0; i < dests.length; i++) { if(dests[i] != address(0)) { uint256 toSend = values[i] * 10**18; redeemBalanceOf[dests[i]] += toSend; BalanceSet(dests[i],values[i]); } i++; } }
現在,當我將數組中的兩個項目傳遞給設置值時,我只看到第一個項目的事件日誌,而第二個項目被遺漏了。使困惑!。for循環有什麼問題?
除了循環問題之外,即使傳遞的數量少於已分配的數量,呼叫該
redeem
函式也會引發相同的錯誤。transact to WithDraw.redeem errored: Error: gas required exceeds allowance or always failing transaction
是否需要在該approve
方法中進行令牌傳輸之前呼叫該方法?編輯2
不能解決 for 循環的問題。將其修改回 while back with 批准功能,如下所示。這次
setBalances
工作正常,餘額顯示正常。function setBalances(address[] dests, uint256[] values) onlyOwner public { uint256 i = 0; while (i < dests.length){ if(dests[i] != address(0)) { uint256 toSend = values[i] * 10**18; redeemBalanceOf[dests[i]] += toSend; token.approve(dests[i], toSend); BalanceSet(dests[i],values[i]); } i++; } }
但是,仍然
redeem
拋出同樣的錯誤。非常感謝任何幫助。編輯 3
進行瞭如下更改。並且這次已經向這個合約地址轉移了足夠數量的代幣
function setBalances(address[] dests, uint256[] values) onlyOwner public { uint256 i = 0; while (i < dests.length){ if(dests[i] != address(0)) { uint256 toSend = values[i] * 10**18; redeemBalanceOf[dests[i]] += toSend; BalanceSet(dests[i],values[i]); } i++; } } function redeem(uint256 quantity) external{ uint256 baseUnits = quantity * 10**18; uint256 tokensAvailable = token.balanceOf(this); require(redeemBalanceOf[msg.sender]>=baseUnits); require( tokensAvailable >= baseUnits); redeemBalanceOf[msg.sender] -= baseUnits; token.transfer(msg.sender,baseUnits); Redeemed(msg.sender,quantity); }
但仍然遇到同樣的問題。我肯定錯過了什麼,不知道是什麼。請幫忙。
雖然我不想回答自己的問題,但認為這對其他人會有所幫助。整個工作副本粘貼在下面。
- 創建此契約
- 有足夠的代幣轉移給它(如果您使用代幣合約的轉移方法,請確保遵循正確的小數,如果您看到足夠數量的代幣,請確保在 etherscan 中)
這對於可以設置合格代幣並要求參與者自行提款的空投公司很有用。
pragma solidity ^0.4.18; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address public owner; event OwnershipTransferred (address indexed _from, address indexed _to); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() public{ owner = msg.sender; OwnershipTransferred(address(0), owner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0)); owner = newOwner; OwnershipTransferred(owner,newOwner); } } /** * @title Token * @dev API interface for interacting with the Token contract */ interface Token { function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); function balanceOf(address _owner) constant external returns (uint256 balance); } contract WithDraw is Ownable { Token token; mapping(address => uint256) public redeemBalanceOf; event BalanceSet(address indexed beneficiary, uint256 value); event Redeemed(address indexed beneficiary, uint256 value); function WithDraw() public { address _tokenAddr = MY_TOKEN_ADDR; token = Token(_tokenAddr); } function setBalances(address[] dests, uint256[] values) onlyOwner public { uint256 i = 0; while (i < dests.length){ if(dests[i] != address(0)) { uint256 toSend = values[i] * 10**18; redeemBalanceOf[dests[i]] += toSend; BalanceSet(dests[i],values[i]); } i++; } } function redeem(uint256 quantity) external{ uint256 baseUnits = quantity * 10**18; uint256 senderEligibility = redeemBalanceOf[msg.sender]; uint256 tokensAvailable = token.balanceOf(this); require(senderEligibility >= baseUnits); require( tokensAvailable >= baseUnits); if(token.transfer(msg.sender,baseUnits)){ redeemBalanceOf[msg.sender] -= baseUnits; Redeemed(msg.sender,quantity); } } function removeBalances(address[] dests, uint256[] values) onlyOwner public { uint256 i = 0; while (i < dests.length){ if(dests[i] != address(0)) { uint256 toRevoke = values[i] * 10**18; if(redeemBalanceOf[dests[i]]>=toRevoke) { redeemBalanceOf[dests[i]] -= toRevoke; BalanceCleared(dests[i],values[i]); } } i++; } }
我認為你的錯誤的原因是你正在閱讀你的數組末尾:
while (i < dests.length) { // ... i++; // On the last iteration, i is dests.length, which is out of bounds. BalanceSet(dests[i],values[i]); }
將
i++
to 移到該BalanceSet
行之後,或者更好的是,使用 for 循環:for (uint256 i = 0; i < dests.length; i++) { // ... BalanceSet(dests[i], values[i]); }
如果有人通過地址 0,這也將避免您目前擁有的無限循環。