Open kroggen opened 2 years ago
A more advanced approach would contain different commands, and the first element would be the command to be executed:
The call
is a normal smart contract call
The store_result
command is used to store the return value in a temporary variable
The assert
is used to ensure that a value is within expected bounds, otherwise the whole transaction fails
Example 1:
[
["call","<address>","function","arg"],
["assert","return_value",">=","250"],
]
Example 2:
[
["call","<address 1>","function1","arg"],
["call","<address 2>","function2","arg"],
["assert","return_value",">=","250"],
]
Example 3:
[
["call","<address 1>","function","arg"],
["store_result","result1"],
["call","<address 2>","function","arg"],
["assert","return_value",">=","result1"],
]
Another possible feature is the use of variables in the arguments, using some form of identification like %variable%
One hard-coded variable can be the result of the last call.
Example usage:
[
["call","<address 1>","function1","arg"],
["call","<address 2>","function2","%last_result%"]
]
When we need to store the result to use later, we use the store_result
command:
[
["call","<address 1>","function1","arg"],
["store_result","result1"],
["call","<address 2>","function2","arg"],
["store_result","result2"],
["call","<address 3>","function3","%result1%","%result2%"]
]
To implement this is easy: iterate over the items in the array and check if they start and end with %
, then replace the content with the variable value
For security reasons, block variable substitution in the first item (command)
The variable substitution also makes the assert
command simpler
To support a variety of use cases, composable transactions should contain many different commands:
-- contract call
call
call.send
call.gas
-- aergo balance and transfer
balance
send
-- variables
let
store
-- tables
get
set
insert (inserts at the end if no position informed)
remove
-- math
add
sub
mul
div
pow
mod
sqrt
-- strings
format (can also be used for concatenation)
substr
find
replace
-- conversions
tobignum
tonumber
tostring
tojson
fromjson
-- assertion
assert
-- conditional execution
if
elif
else
end
-- return result
return
Here is an example script (payload) that would be used to check the returned amount of tokens on a token swap:
["call","<tokenB>","balanceOf"], <-- get the previous balance of token B
["store","balance_before"], <-- store it in a variable
["call","<tokenA>","transfer","<to>","<amount>","swap"], <-- swap token A for token B
["call","<tokenB>","balanceOf"], <-- get the new balance of token B
["sub","%last_result%","%balance_before%"], <-- subtract one balance by the other
["assert","%last_result%",">=","<minimum_amount>"] <-- assert that we got the minimum amount
This feature allows real TRUSTLESS TRANSACTIONS, where the user does not trust even the swap contract!
It can allow for direct token swaps between users A and B, in a complete trustless way
And many other use cases that are possible with this new feature
Execution of these scripts is only enabled on transactions with type MULTICALL
and signed by the user. This means that there is no way an user can execute an script in the context of another user, as the engine uses the account from the transaction as the context.
COMPOSABLE TRANSACTIONS
It is a method to call many contracts in a single transaction.
All the process is atomic. If some of the calls fail, all the transaction is rolled back.
It is used in cases where the user desires to process many things at the same time atomically.
Use Cases
1: Purchase airplane tickets and hotel reservation from different contracts, only if both succeed. If some of the purchases fail, the other is reverted (the user does not want one of them if the other is not acquired).
2: Swap token and buy something with it. If the purchase fails, the user does not want that token.
3: Swap tokens using a split route. If one of the routes fail, revert the other(s). Also check the minimum output in the transaction itself (by adding individual outputs) and revert if not satisfied.
4: Swap to an exact amount of the output token when using a multi-hop route, by either: a. doing a reverse swap of the surplus amount, or b. querying a contract for the right amount to send (between approved range) in the same transaction.
5: Add liquidity to a pool (2 tokens) in a single transaction
6: Trustless swap or purchase - check if the purchased token was received, otherwise revert the transaction
7: Transferring tokens (fungible and/or non-fungible) to multiple recipients at the same time
8: Transferring different tokens (fungible and/or non-fungible) to one recipient in a single transaction
9: Mint many non-fungible tokens (NFTs) in a single transaction
10: Approve contract B to use contract A (token) and then call a function on contract B that handles the resources on contract A (eg: approve and swap, approve and add liquidity) on a single transaction
11: Approve, use resource, and remove approval on a single transaction, with the guarantee that no other operation would happen in between while the resource/token is approved to contract B
Implementation
It may be possible to implement it with backwards compatibility with existing transactions, by adding a new transaction type:
And then the call information is stored in the
payload
in JSON format.It would be a list of calls processed in order
Each call containing the contract address, function to call, and arguments:
Example uses:
Buy 2 products or services on a single transaction:
Acquire token2 via swap and buy a product/service with it:
Add liquidity to a swap pair: