2 releases

0.0.2 Jun 29, 2023
0.0.1 Jun 21, 2023

#741 in Text processing

47 downloads per month

Apache-2.0

15KB
154 lines

Spark Rust SDK

This repository contains the implementation of a predicate-based order book on the Fuel network, along with tests and Spark Rust SDK code.

Components

Predicate + Proxy

This system utilizes a predicate to represent an order that can be filled by anyone. To create an order, the maker sends a coin to the predicate root, which can be unlocked by any transaction that fulfills the order's conditions. These conditions, such as transferring a specific amount of an asset to a receiver, are encoded into the predicate bytecode, making them specific to that particular order.

The order owner can execute the order by spending the predicate coin in a transaction that satisfies the order's conditions. The owner has flexibility in how they use the predicate coin, as long as the transaction output meets the order's conditions and is the first output in the set.

To cancel an order, the maker can spend the predicate coin in a transaction that includes a single coin input signed by the receiver. The transaction consists of two inputs: the signed coin and the predicate coin.

Alice provides information about the price and tokens in this predicate. Additionally, Alice can send additional money to the same predicate root to increase the change amount.

Spark Rust SDK

Designed for seamless integration with CLOB Spark using the Rust programming language, the Spark Rust SDK offers the following functionality:

Getting Predicate Instance

To create a predicate, you need to provide the following configurables:

configurable {
    ASSET0: b256 = ZERO_B256, // Asset that provides the maker (Alice)
    ASSET1: b256 = ZERO_B256, // Asset that provides the taker (Bob)
    MAKER: b256 = ZERO_B256, // Order owner
    PRICE: u64 = 0, // asset1_amount / asset0_amount
    ASSET0_DECIMALS: u8 = 1,
    ASSET1_DECIMALS: u8 = 1,
    PRICE_DECIMALS: u8 = 9, // optional
    MIN_FULFILL_AMOUNT0: u64 = 1, // optional
}

Example:

let usdc_decimals = 6;
let uni_decimals = 9;
let amount0 = 1000_000_000_u64; // 1000 USDC
let amount1 = 300_000_000_000_u64; // 200 UNI
let price_decimals = 9;

let exp = (price_decimals + usdc_decimals - uni_decimals).into();
let price = amount1 * 10u64.pow(exp) / amount0;
println!("Order price: {:?} UNI/USDC", price);

let configurables = LimitOrderPredicateConfigurables::new()
    .set_ASSET0(Bits256::from_hex_str(&usdc_asset_id.to_string()).unwrap())
    .set_ASSET1(Bits256::from_hex_str(&uni_asset_id.to_string()).unwrap())
    .set_ASSET0_DECIMALS(usdc_decimals)
    .set_ASSET1_DECIMALS(uni_decimals)
    .set_MAKER(Bits256::from_hex_str(&alice.address().hash().to_string()).unwrap())
    .set_PRICE(price)
    .set_PRICE_DECIMALS(price_decimals)
    .set_MIN_FULFILL_AMOUNT0(0);

let predicate: Predicate = Predicate::load_from(PREDICATE_BIN_PATH)
    .unwrap()
    .with_configurables(configurables);

Order Creation

async fn create_order(
    wallet: &WalletUnlocked, // Order owner
    proxy_address: &str, // Proxy contract address as a string


    params: ProxySendFundsToPredicateParams, 
    amount: u64, // amount0
) -> Result<FuelCallResponse<()>, fuels::prelude::Error>;

Example:

let params = ProxySendFundsToPredicateParams {
    predicate_root: predicate.address().into(),
    asset_0: usdc.contract_id().into(),
    asset_1: uni.contract_id().into(),
    maker: alice.address().into(),
    min_fulfill_amount_0: 1,
    price,
    asset_0_decimals: 6,
    asset_1_decimals: 9,
    price_decimals: 9,
};

create_order(&alice, PROXY_ADDRESS, params, amount0)
    .await
    .unwrap();

Order Cancellation

pub async fn cancel_order(
    wallet: &WalletUnlocked, // Order owner
    predicate: &Predicate, // Predicate instance
    asset0: AssetId,
    amount0: u64,
) -> Result<FuelCallResponse<()>, fuels::prelude::Error>;

Example:

cancel_order(&alice, &predicate, usdc_asset_id, usdc_mint_amount)
    .await
    .unwrap();

Order Fulfillment

async fn fulfill_order(
    wallet: &WalletUnlocked, // Taker
    predicate: &Predicate, // Predicate instance
    owner_address: &Bech32Address, 
    asset0: AssetId,
    amount0: u64,
    asset1: AssetId,
    amount1: u64,
) -> Result<FuelCallResponse<()>, fuels::prelude::Error>;

Example:

fulfill_order(
    &bob,
    &predicate,
    alice.address(),
    usdc_asset_id,
    usdc_mint_amount, // amount0
    uni_asset_id,
    uni_mint_amount, // amount0
)
.await
.unwrap();

Dependencies

~46–64MB
~1M SLoC