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.