token-wizard
token-wizard copied to clipboard
(Feature) Rework Token Wizard contracts to use the auth_os development framework
Brief Context and Motivation
auth_os is a framework for developing contracts, in which the logic of an application is deployed as a set of libraries, separate from the storage of an application. This structure allows (among other things) the upgrading of application logic, even after it is deployed. Because the logic contracts do not store any information (they are libraries), storage requests are routed through applications by way of a "scripting language." At the moment, this language is very simple - it consists of a list of addresses and calldata to execute, as well as a storage address to store data in. Eventually, the idea is to implement some simple logical structure into this language to allow for additional behavior.
Note that for the brevity's sake, several aspects of auth_os (security/efficiency considerations, as well as several other platform features and mechanisms) are left out, as they are not relevant to this discussion. As such, this post does not provide a full picture of auth_os. If there are additional details or aspects of the platform left out which would clarify the post, please let me know and I will explain them!
Example: "ERC20 transfer-and-approve script"
Given:
- An ERC20 application with (sample) storage address: "0x123"
- A "transfer" logic library:
- with (sample) address: "0x456"
- requiring calldata size: 68 (4-byte function sig + 64-byte address and integer arguments)
- requiring (sample) function signature: "transfer()"
- An "approve" logic library:
- with (sample) address: "0x789"
- requiring calldata size: 68 (4-byte function sig + 64-byte address and integer arguments)
- with (sample) function signature: "approve()"
- A user with address: "0xabc"
- A token recipient with address: "0xdef"
- A token amount - '5'
A user (0xabc) can compile the following script to transfer 5 tokens to a recipient (0xdef) (and then approve the same amount to them, as well): [0x123]-[0x456]-[68]-[transfer()_0xdef_5]-[0x789]-[68]-[approve()_0xdef_5] (This shows the structure of the script only: the actual script is simply encoded as an array of bytes, without the brackets and dashes)
Execution is accomplished through the use of a script parser, similar to the one seen here: https://gist.github.com/wadeAlexC/837549c7e6f438e9badbb00c2408a703 (Note - the above parser does not work with the input syntax described above: it will be modified in the future)
So, generally, interacting through the network is done by passing these scripts into script parsers, which parse and execute several commands. With the addition of a script registry contract, it is possible to "register" created scripts and applications for others to use, as well as update/upgrade/extend already existing scripts. Because the logic of these applications already exists in live contracts, deploying an application (as a user) now simply involves the deployment of a simple storage contract. This is cheaper (~150-200K gas), as well as simpler to deploy. It can also be done from an internal factory, meaning no compiling/deployment is done by POA itself.
The idea is to build the Token Wizard smart contracts using this framework - for modular, upgradable, cheap-to-deploy contracts.
Implementation
One thing we never want users to have to see is the "scripting" portion - having to copy/paste a series of bytes into MetaMask is unusable for most users.
Proposed solutions:
- Creation of "static'' interfaces, which have ERC20/crowdsale ABI, and forward requests to script parsers. In this way, users can interact with a contract the way they are used to - by calling functions at an address.
- Downside: Lacks the modularity inherent in this framework. Deploy interfaces are static, meaning they cannot be modified. Although some allowances can be made here, it is clear that for true implementation, the script parse interface must be used directly.
- Script input is handled by the frontend - requests are made by the user to the script registry to select an application and function, and the appropriate script is generated by the frontend. The user can then sign this script, and release it as a transaction.
- This means that the frontend must understand the script registry contract, which stores very arbitrary data. A 'metadata' section of the script registry contract will be implemented to allow easy reading by the frontend.
Helpful reading
ABI Specification - https://solidity.readthedocs.io/en/develop/abi-spec.html# Assembly Documentation - https://solidity.readthedocs.io/en/develop/assembly.html
Final Notes
auth_os is still a work-in-progress, but the beta is scheduled to be completed on 3/9. Over the next weeks, I am happy to work with the POA front-end team to implement a front-end which is compatible with this new framework.
I would love to hear any questions or comments you may have!
Thanks a lot for the information, @wadeAlexC. There are several things I don't understand yet, surely when the beta and whitepaper are released I'll have more resources to understand it.
For now, I have two questions:
- Your description of a script sounds like a method call (or sequence of method calls), in which you pass the storage location, and the libraries locations, methods and arguments. But then you talk about a "script register". I don't get why would you register that. For example, why would I register the transfer and approval of 5 tokens to a given address?
- This is very minor, but it intrigues me. Where does the 68 come from? You mention 4 bytes for the function signature and 64 for the address and number. But AFAIK, an address is 20 bytes long, and a uint256 is 32 bytes long. That would mean 56 bytes for the arguments. What am I missing?
Sure - my pleasure!
-
Right - the idea of the script registry is not that you're storing specific scripts for specific calls, but rather that you store a script template, so that others can enter their information in the script and use it. For example, the script registry would tell you that to "transfer," you need function signature 'transfer()', that it takes arguments 'address' and 'uint256,' that it returns 'bool,' and that the specific library location is '0x456.' A user can then piece together the correct input script to transfer any amount of tokens to any address (0xdef and 5 were examples for what a completed script would look like).
-
You're exactly right! An address is 20 bytes long - but all calldata arguments are padded to 32 bytes (the exception being the function signature). So you have to account for address as if it were 32 bytes, bring the total to 68.
Oh, I see. Thanks for the answer :+1: