Solidity
使用 .value() 在使用solidity和truffle框架的合約之間匯款時出現編譯錯誤
親愛的積木建造者!我是這個領域的新手,我想實現我的第一個項目,使用重入來模仿著名的 DAO 攻擊。我編寫了兩個智能合約——DAO 和 Hacker。
.value()
但是,由於該方法,我無法編譯我的契約。DAO 包含所有使用者的餘額、地址和姓名
pragma solidity ^0.4.24; contract Dao { struct User { address addr; string name; uint balence; uint8 flag; } .... function addToBalence(string name) public payable{ if(users[msg.sender].flag != 1) addUser(msg.sender,name,0,1); users[msg.sender].balence = users[msg.sender].balence + msg.value; } function showBalence() public returns (uint) { return users[msg.sender].balence; } function withdraw(uint amount) public payable{ if(users[msg.sender].flag != 1) revert("user does not exist"); else if (users[msg.sender].balence >= amount){ msg.sender.call.value(amount)(); users[msg.sender].balence -= amount; } } }
黑客(目前只是普通使用者)假設先存入少量資金,然後使用重入攻擊提取的資金超過他在 DAO 的存款
contract Hacker { Dao dao; address userAddress; // the address of the user, so the money can be transfered string userName; constructor(string userName, address daoAddress) public { dao = Dao(daoAddress); userAddress = msg.sender; userName = userName; } function addToBalence(string name, uint amount) public payable { dao.addToBalence(userName).value(msg.value)(); // ERROR HERE! } function showBalence() public returns(uint){ return dao.showBalence(); } function payout(uint amount) public payable{ dao.withdraw(amount); } }
但是,我
addToBalence
在 Hacker 的契約中的方法出現錯誤,提示說Member "value" not found or not visible after argument-dependent lookup in tuple() - did you forget the "payable" modifier? dao.addToBalence(userName).value(msg.value)();
我非常困惑,因為我已經在 DAO 和 Hacker 的契約中添加了應付修改器。這是否意味著我的方法很簡單,我無法在我的玩具範例中攻擊 DAO 合約?我哪裡做錯了?
你非常接近,你只需要稍微改變你的外部合約函式呼叫的語法
addToBalence(...)
$$ sic $$功能:
//... function addToBalence(string name, uint amount) public payable { dao.addToBalence.value(msg.value)(userName); } //...
請注意,我們在之後刪除了第一組括號
addToBalence
$$ sic $$& 將其中的參數移到了最後一組括號中。
這是您的契約的完整實現(添加了
User
映射和缺少的addUser
功能以使其成功編譯)而沒有該錯誤消息:pragma solidity ^0.4.24; contract Dao { mapping (address => User) public users; struct User { address addr; string name; uint balence; uint8 flag; } function addUser(address _address, string _name, uint _balence, uint8 _flag) public { users[msg.sender].name = _name; users[msg.sender].flag = _flag; users[msg.sender].addr = _address; users[msg.sender].balence = _balence; } function addToBalence(string name) public payable{ if(users[msg.sender].flag != 1) addUser(msg.sender,name,0,1); users[msg.sender].balence = users[msg.sender].balence + msg.value; } function showBalence() public returns (uint) { return users[msg.sender].balence; } function withdraw(uint amount) public payable{ if(users[msg.sender].flag != 1) revert("user does not exist"); else if (users[msg.sender].balence >= amount){ msg.sender.call.value(amount)(); users[msg.sender].balence -= amount; } } } contract Hacker { Dao dao; address userAddress; // the address of the user, so the money can be transfered string userName; constructor(string _userName, address daoAddress) public { dao = Dao(daoAddress); userAddress = msg.sender; userName = _userName; } function addToBalence(string name, uint amount) public payable { dao.addToBalence.value(msg.value)(userName); // ERROR HERE! } }