Skip to content

Instantly share code, notes, and snippets.

@axic
Last active June 19, 2022 20:26
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save axic/528017d2d67801fa669fd75577c2093c to your computer and use it in GitHub Desktop.
Save axic/528017d2d67801fa669fd75577c2093c to your computer and use it in GitHub Desktop.
EIP101 Standard Account code in Solidity
//
// Implementation of the standard account contract as per EIP101 (Cryptocurrency
// abstraction). See: https://github.com/ethereum/EIPs/issues/28
//
// Written by Alex Beregszaszi, use under the MIT license.
//
contract StandardAccount {
uint256 nextSequence = 1;
function() {
// assign calldata variables
bytes memory data = msg.data;
uint len = data.length;
// read out calldata sections
bytes32 v;
bytes32 r;
bytes32 s;
uint256 sequence;
uint256 price;
address to;
assembly {
v := mload(add(data, 32))
r := mload(add(data, 64))
s := mload(add(data, 96))
sequence := mload(add(data, 128))
price := mload(add(data, 160))
to := mload(add(data, 192))
}
// hash the data
bytes32 hash;
assembly {
hash := sha3(add(data, 128), sub(len, 128))
}
// verify signature (the signer address must be the contract address)
if (ecrecover(hash, uint8(v), r, s) != address(this)) {
throw;
}
// confirm sequence
if (sequence != nextSequence) {
throw;
}
// increment for the next sequence
nextSequence++;
// send transaction to the recipient
uint256 gas = msg.gas;
assembly {
call(sub(gas, 50000), to, 0, add(data, 224), sub(len, 192), 0, 0)
}
// pay the miner
// FIXME: calculate gas used
Token(0).transfer(block.coinbase, price * gas);
}
}
contract Token {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() constant returns (uint256 supply) {}
function balanceOf(address _owner) constant returns (uint256 balance) {}
function transfer(address _to, uint256 _value) returns (bool success) {}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}
function approve(address _spender, uint256 _value) returns (bool success) {}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}
}
@chriseth
Copy link

Init of nextSequence can be done in-line.

@chriseth
Copy link

chriseth commented Feb 16, 2017

Line 39 should be: if (ecrecover(hash, uint8(v), r, s) != address(<address of public key>)) { instead of if (ecrecover(hash, uint8(v), r, s) != address(this)) {

@tjayrush
Copy link

I admit to not necessarily knowing what I'm talking about, but what happens if the to account is a recursive attack contract?

@Asone
Copy link

Asone commented Dec 1, 2017

@axic (cc. @vbuterin ) : Few (dumb) questions. Is this draft still valid regarding the last discussions on EIP 208 ?

How should this be implemented in a functional smart-contract ?

contract MyContract is Token, StandardAccount{

  function(){
  ...
  }

 function MyContract(){
  ...
  }

}

like this ?

Also, question made by @tjayrush seems leggit and address a serious concern :p

Thanks for your answers ! Much datalove onto you !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment