One fee market EE to rule them all

There are a couple attributes of a generic asset EE that I think are desirable:

  • The EE can be rigorously tested and formally verified, allowing anyone to deploy an asset with full confidence that the implementation is secure
  • Allows for upgrades to all assets if need be
  • Simplifies the transfer of value between EEs
  • No need to for approve -> transferFrom as assets are first class

I’m imagining this execution environment looking something like the following (just trying to get the broad strokes out, feedback is obviously more than welcome):

GenericAssetEnvState

{
  "assets": [[AssetState, 2**256], MAX_NUM_EE]
}

AssetState

{
  "balances": [u64, 2**256],
  "states": [bytes, 2**256],
  "operations": [OperationCode]
}

OperationCode would represent wasm code that describes how to perform an operation on the token. I imagine the most generic interface would at least support a transfer(to, amount) function which could be defined directly in the EE, but additional functionality (e.g. authorizeOperator(operator)) could be stored as wasm modules that are dynamically linked in during runtime. I believe this kind of linking functionality is something that @axic is working on.

In this world, ShardEther™ could be premined to some address (0x000...0000™) and new tokens could be generated by sending a create transaction to the generic asset EE. These addresses would be valid across all EEs, but each EE, like a fee market EE, would have its own set of balances for each token. Since all / most assets would live within one domain with a consistent addressing scheme, it should be possible to extend the concept of msg.value in the Ethereum EE similarly to how I described in this post:

msg.value

{
  "amount": uint256,
  "asset_address": uint256
  # the EE is implicitly known as the origination EE
}

Now imagine user A wants to send tokens to contract B. User A crafts a transaction using the new msg.value definition and sends it to contract B’s deposit function:

contract B {
  mapping(address => mapping(address => uint256)) deposits;

  function deposit() payable {
    deposits[msg.sender][msg.value.token] += msg.value.amount;
    get_msg_value();
  }
}

The deposit function updates its records and calls get_msg_value(), which is defined as an opcode or EEI host function.

function get_msg_value() {
  token = GenericTransferableTokenInterface(msg.value.token)
  execEnvCall(token.transfer(self, msg.value.amount))
}

The msg.sender and msg.value of the call to contract B is forwarded to the token contract using a delegate call and self is the address of the current execution context, contract B in this example. By nature of signing and sending the original transaction, user A approved the transfer to contract B.