Try the Call Decryption Oracle Locally
What you’ll do
- Start a local test chain (anvil).
- Deploy the on-chain Call Decryption Oracle Contract.
- Start the off-chain Call Decryption Oracle.
- Deploy the on-chain demo contract that talks to the call decryption oracle contract.
- Check the results stored in the demo contract.
Required Installations
You need foundry (for the chain tooling) and jbang (to start a web service with the renderer).
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.
Step-by-Step
1. Launch a local chain for testing
Run:
anvil
After this switch to a new shell.
2. Generate the private and public key (used by the decryption oracle)
2.1. Download the script that will generate a new private key for the decryption oracle.
REPO=https://gitlab.com/finmath/finmath-decryption-oracle/-/raw/main
curl --create-dirs -L $REPO/scripts/generate-keys.sh -o generate-keys.sh
chmod 755 generate-keys.sh
2.1. Generate the private key for the key decryption oracle
export SECRETS_DIR=$(pwd)/secrets
./generate-keys.sh
2.2. Extract the public key (used to encrypt the arguments of function calls)
CERT="$SECRETS_DIR/oracle.crt.pem"
export PUBLIC_KEY="$(openssl x509 -in "$CERT" -noout -pubkey | openssl pkey -pubin -outform DER | xxd -p -c 1000000 | tr -d '\r\n' | sed 's/^/0x/')"
echo "$PUBLIC_KEY"
3. Deploy the Key Decryption Oracle Contract and the Demo Contract
3.1. Download CallDecryptionOracle.sol and CallDecryptionOracleRouter.sol
Run:
REPO=https://gitlab.com/finmath/finmath-decryption-oracle/-/raw/main/oracle-execution
curl --create-dirs -L $REPO/src/main/solidity/ICallDecryptionOracle.sol -o ICallDecryptionOracle.sol
curl --create-dirs -L $REPO/src/main/solidity/ICallDecryptionOracleRouterDemo.sol -o ICallDecryptionOracleRouterDemo.sol
curl --create-dirs -L $REPO/src/main/solidity/CallDecryptionOracle.sol -o CallDecryptionOracle.sol
curl --create-dirs -L $REPO/src/main/solidity/CallDecryptionOracleRouter.sol -o CallDecryptionOracleRouter.sol
3.2. Build and deploy the contract CallDecryptionOracle
Run:
export RPC_URL="http://127.0.0.1:8545"
export PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
OWNER=$(cast wallet address --private-key "$PRIVATE_KEY")
CONTRACT_PATH=.
CONTRACT_NAME=CallDecryptionOracle
ORACLE_CONTRACT=$(
forge create --use 0.8.23 --broadcast --root . --json "$CONTRACT_PATH/$CONTRACT_NAME.sol:$CONTRACT_NAME" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
--constructor-args "$OWNER" "$PUBLIC_KEY" \
| tr -d '\r\n' \
| sed -nE 's/.*"deployedTo"[[:space:]]*:[[:space:]]*"(0x[0-9a-fA-F]{40})".*/\1/p'
)
echo "Contract deployed at $ORACLE_CONTRACT"
3.3. Build and deploy the contract CallDecryptionOracleRouter
Run:
export RPC_URL="http://127.0.0.1:8545"
export PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
OWNER=$(cast wallet address --private-key "$PRIVATE_KEY")
CONTRACT_PATH=.
CONTRACT_NAME=CallDecryptionOracleRouter
ROUTER_CONTRACT=$(
forge create --use 0.8.23 --via-ir --broadcast --root . --json "$CONTRACT_PATH/$CONTRACT_NAME.sol:CallDecryptionOracleRouter" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
--constructor-args "$ORACLE_CONTRACT" \
| tr -d '\r\n' \
| sed -nE 's/.*"deployedTo"[[:space:]]*:[[:space:]]*"(0x[0-9a-fA-F]{40})".*/\1/p'
)
echo "Contract deployed at $ROUTER_CONTRACT"
4. Launch the CallDecryptionOracle service (locally)
4.1. Launch the CallDecryptionOracle service (locally)
Run (in the same shell that deployed the contract and the same folder as $SECRETS_DIR):
jbang --java 21 -Dethereum.rpcUrl=http://127.0.0.1:8545 -Dethereum.chainId=1337 -Dethereum.calldecryptionoracle.contract=$ORACLE_CONTRACT -Dethereum.calldecryptionoracle.stateFile=oracle-state.txt net.finmath:finmath-decryption-oracle-encrypted-hashed-execution:2.5.5 > jbang.log 2>&1 </dev/null &
4.2. Show the log of the KeyDecryptionOracle
(Optional): In a new Window / shell, in the same directory, run:
tail -f jbang.log
This allows you to observe the log of the decryption oracle service.
Then return to the previous shell that deployed the contract (this is important, because we will use the environment variables $ORACLE_CONTRACT and $ROUTER_CONTRACT).
The decryption oracle is up and running now, we now perform a test, generating encrypted arguments, storing them, requesting decryption and execution of a function call.
5. Encrypted Arguments Generation
Pasting the following lines in your shell (e.g. bash) will generate the encrypted arguments for (uint256) 20, (string) “Peach” (uint256) 990. It will construct a call descriptor for a function that has that signature.
ARGS_PLAIN=$(cast abi-encode "func(uint256,string,uint256)" 20 "Peach" 990)
ARGS_HASH=$(cast keccak "$ARGS_PLAIN")
export ARGS_DESCRIPTOR=$(cast abi-encode "wrap(address[],bytes)" [] $ARGS_PLAIN)
export ORACLE_PUBLIC_KEY=$(cast call "$ORACLE_CONTRACT" "getPublicKey()(bytes,bytes32)" --rpc-url "$RPC_URL" | head -n 1)
ENCRYPTED_ARGS=$(jbang net.finmath:finmath-decryption-oracle-base:2.5.5:cli)
FEE_CALL_DECRYPT=$(cast call "$ORACLE_CONTRACT" "feeCall()(uint256)" --rpc-url "$RPC_URL")
ECHO $FEE_CALL_DECRYPT
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)
printf "\n\n\e[1mDemo Call Descriptor:\e[0m\n$DEMO_CALL_DESCRIPTOR\n\n\e[1mDemo Encrypted Arguments:\e[0m\n$ENCRYPTED_ARGS\n\n\e[1mArgs Hash:\e[0m\n$ARGS_HASH\n\n\e[1mFee (for Decrypt) in Wei (1E18):\e[0m\n$FEE_CALL_DECRYPT\n\n"
6. Use the encrypted arguments in the demo contract
6.1 Store the encrypted arguments for later use in a function call
Run:
ID=5
cast send "$ROUTER_CONTRACT" \
"store(uint256,bytes,bytes,bytes32)" $ID $DEMO_CALL_DESCRIPTOR $ENCRYPTED_ARGS $ARGS_HASH \
--rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy --gas-price 1gwei --gas-limit 1000000
6.2 Define a Helper Function to Fetch the Result form the Demo Contract
We define a function that fetches the result from the demo contract.
After this function has been defined we may fetch a result from the contract via oracle_get_result <id>.
Run:
oracle_get_result () {
local id="$1"
local sig='getResult(uint256)(uint256,address,address,bytes4,bytes,bytes32,uint256,bytes,bytes32,bool)'
# temp file to avoid subshell issues
local tmpfile
tmpfile="$(mktemp)"
cast call "$ROUTER_CONTRACT" "$sig" "$id" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" > "$tmpfile" || {
rm -f "$tmpfile"
echo "cast call failed" >&2
return 1
}
vars=(phase caller targetContract targetSelector argsEncrypted argsHash requestId argsPlain argsHashComputed routingSuccess)
{
for v in "${vars[@]}"; do
IFS= read -r "$v" || break
done
} < "$tmpfile"
rm -f "$tmpfile"
# Optional pretty print
cat <<RESULT
phase.............: $phase (0=new, 1=stored, 2=requested, 3=callback, 4=routed, 5=final)
caller............: $caller
targetContract....: $targetContract
targetSelector....: $targetSelector
argsEncrypted.....: $argsEncrypted
argsHash..........: $argsHash
requestId.........: $requestId
argsPlain.........: $argsPlain
argsHashComputed..: $argsHashComputed
routingSuccess....: $routingSuccess
RESULT
}
6.3 Fetch the Result
Run:
oracle_get_result $ID
This will fetch the rsult. The encrypted key will be stored under $encryptedKey.
7. Decryption of the Arguments
7.1 Trigger decryption of the arguments (through the demo contract)
Run:
cast send "$ROUTER_CONTRACT" \
"decrypt(uint256)" $ID \
--rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy --gas-price 1gwei --gas-limit 300000
7.2 Fetch the Result
Run:
oracle_get_result $ID
This will fetch and display the result.
Repeating this call, you may first observe that “phase 2 (=requested)”, then a few seconds later “phase 3 (=callback)”. In the log of the decryption oracle service you will see the request and the fulfillment.
8. Execution of a Function Call
8.1 Trigger execution of a function call with the decrypted arguments (through the demo contract)
Run:
cast send "$ROUTER_CONTRACT" \
"execute(uint256)" $ID \
--rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy --gas-price 1gwei --gas-limit 300000
8.2 Fetch the Result
Run:
oracle_get_result $ID
This will fetch and display the result.
9. Routing
9.1 Fetch the Results of the Routing
The demo contract automatically triggers a rounting a function with
typed arguments (uint256,string,uint256) where we should recover the
arguments that were encrypted above.
Run:
cast call "$ROUTER_CONTRACT" "getDemoTargetValues(uint256)(uint256,string,uint256)" "$ID" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY"
Last updated: 2025‑12‑24
