У пользователя thadao.slack.com возникли проблемы с выводом возмещения средств через контактное лицо DAO Withdrawal.
Я проверил WithdrawDAO
контакт и заметил, что есть много других неудачных транзакций:
Почему не удается вернуть пользователю The DAO в ETH?
В этом случае пользователь использовал кошелек Jaxx для возврата средств.
Смотрите также:
Проблема. Похоже, что в некоторых кошельках возникают ошибки округления.
Решение . Решение состоит в том, чтобы утвердить сумму, превышающую баланс в The DAO. Пользователь должен связаться с Jaxx, если эта проблема возникает в рамках функций кошелька Jaxx.
В качестве альтернативы пользователь может выполнить вывод, используя один из 4 методов, описанных в разделе Как мне конвертировать мои токены DAO в эфиры, используя контракт на вывод средств после хард-форка?
Обратите внимание , что большинство неудачных транзакций DAO -> ETH связаны с нулевым балансом DAO в DAO. Это может быть связано с тем, что пользователь уже осуществил возврат средств DAO -> ETH или выполняет возврат средств на неправильные учетные записи.
Контракт WithdrawDAO
полагается на то, что пользователь выполняет DAO, approve(...)
чтобы позволить WithdrawDAO
контракту передавать токены со счета пользователя на себя в обмен на возврат эквивалентной суммы на счет пользователя. Из-за ошибки округления где-то в процессе утверждается сумма меньше остатка, и это вызывает ошибку в процессе вывода средств.
Я проверил один из неудачных выводов с сообщением об ошибке, Warning! Error encountered during contract execution [Bad jump destination]
как показано ниже:
Я запустил следующий скрипт geth console
, и он подтвердил, что в утвержденной для перевода сумме и остатке не хватает 341 вей.
var theDAOABIFragment = [{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"type":"function"}, {"type":"function","outputs":[{"type":"uint256","name":"balance"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner"}],"constant":true}];
undefined
> var theDAOAddress = "0xbb9bc244d798123fde783fcc1c72d3bb8c189413"
undefined
> var theDAO = web3.eth.contract(theDAOABIFragment).at(theDAOAddress);
undefined
> var owner = "0x2de4452025f0f2c92f0cde55c0990e44abdc55b5".toLowerCase();
undefined
> var spender = "0xbf4ed7b27f1d666546e30d74d50d173d20bca754".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
8333333333333332992
> balance;
8333333333333333333
> difference;
-341
>
В коде ниже видно, что WithdrawDAO.withdraw()
звонки TheDAO.transferFrom(...)
с полным балансом, но TheDAO.transferFrom(...)
есть следующие проверки:
balances[_from] >= _amount
&& allowed[_from][msg.sender] >= _amount
Что не позволит снять баланс, превышающий утвержденную сумму.
Вот еще одна неудачная транзакция :
> var owner = "0x1062eecd8d3ce44a469eddb82f309971dd02ec92".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
41338832000199999488
> balance;
41338832000200000000
> difference;
-512
И еще одна неудачная транзакция :
> var owner = "0xe69619509a867775bf2c8b96408a82157fda695d".toLowerCase();
undefined
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
2051130434782608640
> balance;
2051130434782608695
> difference;
-55
И еще одно :
> var owner = "0x34657ab7e8a352e7c0a08c9a14a7f07a15ae98ce".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
20682758620689653760
> balance;
20682758620689655172
> difference;
-1412
Некоторые пользователи не одобрили перевод до вызова вывода средств :
> var owner = "0x98ba5387be9f93d777b52aef0d9c579851ee8142".toLowerCase();
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
0
> balance;
39485714285714
> difference;
-39485714285714
>
А у некоторых есть нулевые остатки для утверждения или перевода :
> var owner = "0x9c0af3a6f4a2266b3e2cf1cf81d30258e3862481".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
0
> balance;
0
> difference;
0
>
WithdrawDAO
_Ниже приведен фрагмент контракта WithdrawDAO, показывающий withdraw()
метод:
contract WithdrawDAO {
...
function withdraw(){
uint balance = mainDAO.balanceOf(msg.sender);
if (!mainDAO.transferFrom(msg.sender, this, balance) || !msg.sender.send(balance))
throw;
}
...
}
The DAO
ДоговорНиже приведены фрагменты из контакта DAO , показывающие только соответствующие классы и методы:
contract TokenInterface {
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
...
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) constant returns (uint256 balance);
...
/// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
/// is approved by `_from`
/// @param _from The address of the origin of the transfer
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return Whether the transfer was successful or not
function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);
/// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
/// its behalf
/// @param _spender The address of the account able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address _spender, uint256 _amount) returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens of _owner that _spender is allowed
/// to spend
function allowance(
address _owner,
address _spender
) constant returns (uint256 remaining);
...
}
contract Token is TokenInterface {
...
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
function transferFrom(
address _from,
address _to,
uint256 _amount
) noEther returns (bool success) {
if (balances[_from] >= _amount
&& allowed[_from][msg.sender] >= _amount
&& _amount > 0) {
balances[_to] += _amount;
balances[_from] -= _amount;
allowed[_from][msg.sender] -= _amount;
Transfer(_from, _to, _amount);
return true;
} else {
return false;
}
}
function approve(address _spender, uint256 _amount) returns (bool success) {
allowed[msg.sender][_spender] = _amount;
Approval(msg.sender, _spender, _amount);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
}
...
// The DAO contract itself
contract DAO is DAOInterface, Token, TokenCreation {
...
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
if (isFueled
&& now > closingTime
&& !isBlocked(_from)
&& transferPaidOut(_from, _to, _value)
&& super.transferFrom(_from, _to, _value)) {
return true;
} else {
throw;
}
}
...
}