oasisprotocol / oasis-sdk

Official SDK for the Oasis Network.
Apache License 2.0
76 stars 20 forks source link

Add ROFL query to example and docs #1999

Open matevz opened 2 months ago

matevz commented 2 months ago

Show how EVM queries to Sapphire can be used in ROFL.

Taken from the ROFL example, sth like this may work to fetch the last submitted observation:

let res = env.client().query(
            0,
            "evm.SimulateCall",
            module_evm::types::SimulateCallQuery {
                gas_price: 10_000.into(),
                gas_limit: 100_000,
                caller: module_evm::derive_caller::from_sigspec(&SignatureAddressSpec::Secp256k1Eth(sdk_pub_key)).unwrap(),
                address: Some(ORACLE_CONTRACT_ADDRESS.parse().unwrap()),
                value: 0.into(),
                 data: [
                   ethabi::short_signature("getLastObservation", &[]).to_vec(),
                   ethabi::encode(&[]),
                 ].concat(),
            },
        ).await?;
        println!("{:?}", res);

Based on this code https://github.com/oasisprotocol/oasis-sdk/blob/main/runtime-sdk/modules/evm/src/mock.rs#L168-L179

Related https://github.com/oasisprotocol/oasis-web3-gateway/pull/625

ahmedhamedaly commented 1 month ago

This is the working code snippet to read the getLastObservation view function from the ROFL oracle example.

async fn get_last_observation(self: Arc<Self>, env: Environment<Self>) -> Result<(u128, u64)> {
    let data: Vec<u8> = [
        ethabi::short_signature("getLastObservation", &[]).to_vec(),
        ethabi::encode(&[]),
    ]
    .concat();

    let sdk_pub_key =
        secp256k1::PublicKey::from_bytes(env.signer().public_key().as_bytes()).unwrap();

    let caller = module_evm::derive_caller::from_sigspec(&SignatureAddressSpec::Secp256k1Eth(
        sdk_pub_key,
    ))
    .unwrap();

    let res: Vec<u8> = env
        .client()
        .query(
            env.client().latest_round().await?.into(),
            "evm.SimulateCall",
            module_evm::types::SimulateCallQuery {
                gas_price: 10_000.into(),
                gas_limit: 100_000,
                caller,
                address: Some(ORACLE_CONTRACT_ADDRESS.parse().unwrap()),
                value: 0.into(),
                data,
            },
        )
        .await?;

    let decoded = ethabi::decode(
        &[
            ethabi::ParamType::Uint(128), // _value
            ethabi::ParamType::Uint(256), // _block
        ],
        &res,
    )
    .map_err(|e| anyhow::anyhow!("Failed to decode response: {}", e))?;

    let value = decoded[0].clone().into_uint().unwrap().as_u128();
    let block = decoded[1].clone().into_uint().unwrap().as_u64();

    Ok((value, block))
}
match self.get_last_observation(env).await {
    Ok((value, block)) => {
        let price = value as f64 / 1_000_000.0;
        println!(
            "Last observation: ${:.6} ROSE/USDT at block {}",
            price, block
        );
    }
    Err(err) => println!("Failed to get last observation: {:?}", err),
}