Skip to content

Instantly share code, notes, and snippets.

@axic
Last active December 15, 2021 03:14
Show Gist options
  • Save axic/16158c5c88fbc7b1d09dfa8c658bc363 to your computer and use it in GitHub Desktop.
Save axic/16158c5c88fbc7b1d09dfa8c658bc363 to your computer and use it in GitHub Desktop.
ewasm “WRC20” token contract coding challenge

ewasm “WRC20” token contract coding challenge

This document describes a simple contract in pseudocode and gives a couple of test cases for it.

The challenge is designed to be fairly easy to implement in a language of choice, compiled to wasm and interacted with. It is loosely based on the ERC20 token standard, named "WRC20", where the W stands for WebAssembly.

External interface

The contract has two features:

  • querying the balance of an address
  • transfering tokens

Upon deployment the address 0xeD09375DC6B20050d242d1611af97eE4A6E93CAd (private key: 0xdffca753e40d47521d2dd94fe56b0131051d91df614ef0a5e1c301ba9575c550) should have a balance of 1000000.

The interface is loosely based on the Ethereum contract ABI, but is geared towards non-256-bit systems:

  • has a 32 bit selector, which is the first 32 bits of the keccak-256 hash of the signature
  • has multiple data types, but here we only use address (160 bit bytestring) and uint64 a 64 bit number

The two methods:

  • balance is encoded as keccak256("balance(address):(uint64)")[0, 4] address and returns uint64
  • transfer is encoded as keccak256("transfer(address,uint64)")[0, 4] address value

For test cases see below.

Logic in pseudocode

// main ewasm entry point
fun main() { 
  if (eei_calldatasize() < 4)
    eei_revert(0, 0)
  let selector = eei_calldatacopy(0, 4)
  switch selector {
    case 0x9993021a:
      do_balance()
    case 0x5d359fbd:
      do_transfer()
    default:
      eei_revert(0, 0)
  }
}

fun do_balance() {
  if (eei_calldatasize() != 24)
    eei_revert(0, 0)

  let address = eei_calldatacopy(4, 20)
  // make sure that address is 160 bits here,
  // but storage key is 256 bits so need to pad it somehow
  let balance = eei_storageload(address)
  eei_return(balance)
}

fun do_transfer() {
  if (eei_calldatasize() != 32)
    eei_revert(0, 0)

  let sender = eei_sender()
  let recipient = eei_calldatacopy(4, 20)
  let value = eei_calldatacopy(24, 8)
  let sender_balance = eei_storageload(sender)
  let recipient_balance = eei_storageload(recipient)
  
  if (sender_balance < value)
    eei_revert(0, 0)

  sender_balance -= value
  recipient_balance += value

  eei_storagestore(sender, sender_balance)
  eei_storagestore(recipient, recipient_balance)
}

Test cases

  1. Query balance of 0xeD09375DC6B20050d242d1611af97eE4A6E93CAd

Input: 9993021aed09375dc6b20050d242d1611af97ee4a6e93cad

Output: 00000000000f4240

  1. Transfer 500000 to 0xe929CF2544363bdCEE4a976515d5F97758Ef476c (sender as above)

Input: 5d359fbde929cf2544363bdcee4a976515d5f97758ef476c7a120

Output: empty

  1. Query balance of 0xeD09375DC6B20050d242d1611af97eE4A6E93CAd

Input: 9993021aed09375dc6b20050d242d1611af97ee4a6e93cad

Output: 000000000007a120

  1. Query balance of 0xe929CF2544363bdCEE4a976515d5F97758Ef476c

Input: 9993021ae929cf2544363bdcee4a976515d5f97758ef476c

Output: 000000000007a120

@ligi
Copy link

ligi commented Jul 12, 2018

I wonder a bit about keccak256("balance(address):(uint64)")[0, 4] address

Usually the return type is not part of the function signature - is this different in eWASM? Would love a link with some more information about this - could not find anything so far.

@axic
Copy link
Author

axic commented May 9, 2019

Usually the return type is not part of the function signature - is this different in eWASM?

Yes, this was trying to fix a shortcoming of the ABI.

@axic
Copy link
Author

axic commented May 9, 2019

Alternatively to maintain tooling compatibility we could use the standard "Contract ABI" for ERC20 with the only change that balances are uint64 and not uint256.

In this case values would be 256-bit long, but since the type is uint64 when parsing in a contract it could ignore the leading zeroes and could just returned leading zeroes without having bignum support.

@jwasinger
Copy link

Usually the return type is not part of the function signature - is this different in eWASM?

Yes, this was trying to fix a shortcoming of the ABI.

@axic can you explain this?

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