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 choosen clientId
  • decrypt(clientId): trigger the decryption of the stored encryptedArgs and validate the result against argsHash.
  • execute(clientId): execute the method specifed by the callDescriptor with 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.