Sui Move V0

Deployed Contracts

Testnet

Mainnet

Usage

to use the contract, you must pass in the data you receive from the Stork API. For example, this response:

{
    "0x51aa9e9c781f85a2c0636a835eb80114c4553098": {
        "external_asset_id": "XRPUSD",
        "price": "360500000000000000",
        "timestamped_signature": {
            "signature": {
                "r": "0x25a434cbece35d96bed07995de0689442cdf102d34b91e64e20362e00160ffd1",
                "s": "0x4007c7528fa2164e0ed95b6ae89716d2eb929ea02101f09eb7822a8a68c968a8",
                "v": "0x1b"
            },
            "timestamp": "1678911180",
            "msg_hash": "0x5c505a54e938cf4030057f4d8e5817f34f126e807455d26b266373f331f76197"
        }
    }
}

Produces the following inputs:

FieldValue

Oracle Name

0x51aa9e9c781f85a2c0636a835eb80114c4553098

Asset Pair

XRPUSD

Price

360500000000000000

Timestamp

1678911180

Signature

25a434cbece35d96bed07995de0689442cdf102d34b91e64e20362e00160ffd14007c7528fa2164e0ed95b6ae89716d2eb929ea02101f09eb7822a8a68c968a81b

where signature is concat(r,s,v) from the response.

Details

Stork takes advantage of Sui Move's ability to verify ECDSA signatures to offer access to the entire Stork catalog. To verify Stork prices, you can use the following code which is also what is deployed to the sample contracts listed on this page.

module sui_verify_signature::verify{
    use sui::hash;
    use std::bcs;
    use sui::tx_context::{Self, TxContext};
    use sui::transfer;
    use sui::ecdsa_k1;
    use std::vector;
    use sui::object::{Self, UID};


    public entry fun verify_sig(
        oracle_string: vector<u8>, 
        asset_pair_id: vector<u8>, 
        price: u256, 
        timestamp: u256, 
        signature: vector<u8>,
        ctx: &mut TxContext
    ) {

        // Build the message from the components
        let pack = std::vector::empty<u8>(); 
        std::vector::append(&mut pack, oracle_string);
        std::vector::append(&mut pack, asset_pair_id);
        std::vector::append(&mut pack, pack_u256(timestamp));
        std::vector::append(&mut pack, pack_u256(price));

        // Hash the message
        let hashed_message  = hash::keccak256(&pack); 

        // Prepend the message with the Ethereum Signed Message prefix
        let padder = b"\x19Ethereum Signed Message:\n32";

        // Combine the message and the prefix
        std::vector::append(&mut padder, hashed_message);

        let response : bool = erecover_to_eth_address_and_reply(signature, padder) == oracle_string;
        // event::emit(VerifiedEvent {is_verified: response});

        let addr_object = Output {
            id: object::new(ctx),
            value: response,
        };

        // Transfer an output data object holding the address to the recipient.
        transfer::public_transfer(addr_object, tx_context::sender(ctx))

    }

    /* 
     * Library Methods
     */

    struct VerifiedEvent has copy, drop {
        is_verified: bool,
    }

    struct MyEvent has copy, drop {
        value: vector<u8>
    }

    struct Output has key, store {
        id: UID,
        value: bool
    }

    fun pack_u256(value_to_pack: u256) : vector<u8> {
        let value_vector = bcs::to_bytes(&value_to_pack);
        std::vector::reverse(&mut value_vector);
        value_vector
    }

    // Recovers and returns the signing address
    public fun erecover_to_eth_address_and_reply(signature: vector<u8>, raw_msg: vector<u8>) : vector<u8> {
        let v = vector::borrow_mut(&mut signature, 64);
        if (*v == 27) {
            *v = 0;
        } else if (*v == 28) {
            *v = 1;
        } else if (*v > 35) {
            *v = (*v - 1) % 2;
        };

        let pubkey = ecdsa_k1::secp256k1_ecrecover(&signature, &raw_msg, 0);
        let uncompressed = ecdsa_k1::decompress_pubkey(&pubkey);


        // Take the last 64 bytes of the uncompressed pubkey.
        let uncompressed_64 = vector::empty<u8>();
        let i = 1;
        while (i < 65) {
            let value = vector::borrow(&uncompressed, i);
            vector::push_back(&mut uncompressed_64, *value);
            i = i + 1;
        };

        // Take the last 20 bytes of the hash of the 64-bytes uncompressed pubkey.
        let hashed = hash::keccak256(&uncompressed_64);
        let addr = vector::empty<u8>();
        let i = 12;
        while (i < 32) {
            let value = vector::borrow(&hashed, i);
            vector::push_back(&mut addr, *value);
            i = i + 1;
        };

        (addr)
    }
    
}

Last updated