Usage
⚠️ Before you continue: Please read the Disclaimer.
By using this site, software, or contracts, you acknowledge that you have read and accepted it.
Requirements
We will illustrate the necessary steps via small commandline executions using cast and jbang
Required Installations
You need foundry (for the chain tooling) and jbang (to launch a tool that encrypts the arguments).
For installation instructions see the setup page.
Apart from this we assume that openssl, cat, tr, xxd and sed are present.
The following commands should be run in a shell (macOS Terminal, Windows GitBash). You may use the copy button and just paste them into the shell.
In the following we construct the call descriptor and the encrypted arguments step-by-step.
Encrypt Arguments
1) Create plain representation of the arguments
Create a bytes representation of your arguments via abi.encode.
For example, for (uint256(20), string("Peach"), uint256(990)) this would be in Solidity
bytes memory encoded = abi.encode(uint256(20), string("Peach"), uint256(990));
You can do this on the command line via cast. For example, to encode an integer value (20), a string (“Peach”), an integer (990) you can write
ARGS_PLAIN=$(cast abi-encode "func(uint256,string,uint256)" 20 "Peach" 990)
echo $ARGS_PLAIN
This example would result in
0x0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000000055065616368000000000000000000000000000000000000000000000000000000
This is the value of argsPlain.
2) Calculate the Hash
Calculate the hash value for the plain arguments. This can be done via
ARGS_HASH=$(cast keccak "$ARGS_PLAIN")
echo $ARGS_HASH
This example would result in
0xd8e3ac299d2e28bbd43fb9fcad763e6ad27c1cbab4e50c24618138452b4ae75c
This is the value of argsHash.
3) Build the arguments descriptor
The final argument descriptor may contain an array of addresses with eligibleCallers. If we leave it empty, we just set
export ARGS_DESCRIPTOR=$(cast abi-encode "wrap(address[],bytes)" [] $ARGS_PLAIN)
echo $ARGS_DESCRIPTOR
Next step is to encrypt this argument descriptor.
4) Fetch the public key for encryption
A key decryption oracle is available on different networks. The oracle itself provides the public key that can be used to encrypt argument. You can fetch it directly from the oracle.
Depending on the choosen network set:
Ethereum Mainnet
RPC_URL="https://ethereum-rpc.publicnode.com"
ORACLE_CONTRACT=0x13E6464A85a63c9214a4F04cd942466F35D17E54
Polygon Mainnet
RPC_URL="https://polygon-rpc.com"
ORACLE_CONTRACT=0x22a687a3a0F958AccC1395C4D134F297eaCa1B2B
Sepolia (Ethereum Testnet)
RPC_URL="https://ethereum-sepolia-rpc.publicnode.com"
ORACLE_CONTRACT=0x668a5e0eE0dD80F08AE7cf7D91Af84d6bB28f70D
Amoy (Polygon Testnet)
RPC_URL="https://rpc-amoy.polygon.technology"
ORACLE_CONTRACT=0x27aF9135aF9a7FEe7f9dde4d595E200B0c602576
With these definition you can fetch the current public key via
export ORACLE_PUBLIC_KEY=$(cast call "$ORACLE_CONTRACT" "getPublicKey()(bytes,bytes32)" --rpc-url "$RPC_URL" | head -n 1)
echo $ORACLE_PUBLIC_KEY
5) Encrypt the ArgumentDescriptor
ENCRYPTED_ARGS=$(jbang net.finmath:finmath-decryption-oracle-base:1.3.0:cli)
echo $ENCRYPTED_ARGS
6) Build the CallDescriptor
Specific the target contract (the contract that should receive the decrypted arguments)
and the target method (the function name, e.g. myFunction on contract 0x1234567812345678123456781234567812345678). The signature of this function
needs to be (uint256,bytes). The second argument is an abi-encode of a typed argument vector.
TARGET_CONTRACT=0x1234567812345678123456781234567812345678
TARGET_METHOD="myFunction"
TARGET_VALID_UNTIL_BLOCK=0
where myFunction is the name of the method.
With these definitions specify the SELECTOR and build the CallDescriptor via
SELECTOR=$(cast sig "$TARGET_METHOD(uint256,bytes)")
CALL_DESCRIPTOR=$(cast abi-encode "CallDescriptor(address,bytes4,uint256)" $TARGET_CONTRACT $SELECTOR $TARGET_VALID_UNTIL_BLOCK)
echo "$CALL_DESCRIPTOR"
Done
The output of step 6 (the CALL_DESCRIPTOR) and step 5 (the ENCRYPTED_ARGS) can now be passed
to a smart contract of your own and stored for later execution.
Once the pre-conditions of your specific use case are fulfilled, your smart contract can call the oracles requestCall method
function requestCall(CallDescriptor calldata callDescriptor, EncryptedHashedArguments calldata encArgs, bytes calldata secondFactor) external payable returns (uint256 requestId);
and trigger the call the specific function (in the example above func(uint256,bytes)) on the specified TARGET_CONTRACT,
where the second argument will be the ARGS_PLAIN (the decrypted arguments).
Your target contract may resolve the typed arguments using an abi-decode or route to a correspondingly typed function like
(bool success, ) = address(this).call(abi.encodePacked(this.finalTargetFunction.selector, argsPlain));
and continue with its business logic from there.
Continue (1): Router
We provide a generic router for testing purposes that may also used for demonstration.
The router provides three methods:
store(clientId, callDescriptor, encryptedArgs, argsHash): store a callDescriptor, encryptedArgs, argsHash under a freely choosenclientIddecrypt(clientId): trigger the decryption of the storedencryptedArgsand validate the result againstargsHash.execute(clientId): execute the method specifed by thecallDescriptorwith the decrypted arguments.
The router provides a view getResults to view the current state associated with a clientId.
An instance of the router is available at the following address:
Ethereum Mainnet
RPC_URL="https://ethereum-rpc.publicnode.com"
ROUTER_CONTRACT=0xcA7E032a351D654c00A8262BCb1Fe01c8c351203
Polygon Mainnet
RPC_URL="https://polygon-rpc.com"
ROUTER_CONTRACT=0x07f873654A0C7aDfe2F2DBA0d5d453DEf263dB60
Sepolia (Ethereum Testnet)
RPC_URL="https://ethereum-sepolia-rpc.publicnode.com"
ROUTER_CONTRACT=0xdd3292f3743002CA4e2F637C09D4b6C11F1fA094
Amoy (Polygon Testnet)
RPC_URL="https://rpc-amoy.polygon.technology"
ROUTER_CONTRACT=0xBEFA3d598cC127b8Bc7b9E2dCDc29349d68a39A4
Continue (2): Demo
For demonstation purposes the router may be choosen as target contract
for the routed call. For this it offers a method demoTargetFunction(uint256,string,uint256).
If the plain arguments are initialized to this selector, you can observe
the three arguments via the view getResultsDemo(cliendId).
The required call descriptor is given by
DEMO_TARGET_CONTRACT=$ROUTER_CONTRACT
DEMO_TARGET_METHOD="demoTargetFunction"
DEMO_TARGET_VALID_UNTIL_BLOCK=0
DEMO_SELECTOR=$(cast sig "$DEMO_TARGET_METHOD(uint256,string,uint256)")
DEMO_CALL_DESCRIPTOR=$(cast abi-encode "CallDescriptor(address,bytes4,uint256)" $DEMO_TARGET_CONTRACT $DEMO_SELECTOR $DEMO_TARGET_VALID_UNTIL_BLOCK)
echo $DEMO_CALL_DESCRIPTOR
See the Try It page for a test via Remix.
