Crate stablebond_sdk

Crate stablebond_sdk 

Source
Expand description

To get started quickly with the stablebond SDK, you can use the following methods to quickly build transactions for the fundamentals of etherfuse stablebonds.

Including

  • Purchasing a bond
  • Requesting a redemption
  • Redeeming a bond
  • Create a purchase order
  • Redeeming a purchase order

§Examples

use crate::{
    accounts::{Bond, BondMultisigMeta, PaymentFeed},
    find_bond_multisig_meta_pda, find_bond_pda, find_config_pda, find_issuance_pda, find_kyc_pda,
    find_nft_issuance_vault_pda, find_payment_feed_pda, find_payment_pda, find_payout_pda,
    find_purchase_order_pda, CreatePurchaseOrderV2, CreatePurchaseOrderV2InstructionArgs,
    PurchaseBondV2, PurchaseBondV2InstructionArgs, RedeemBond, RedeemPurchaseOrder,
    RequestRedemptionV2, RequestRedemptionV2InstructionArgs,
};
use anyhow::Result;
use mpl_token_metadata::accounts::{MasterEdition, Metadata};
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{message::Message, signature::Keypair};
use solana_sdk::{pubkey::Pubkey, signer::Signer};
use solana_sdk::{system_program, transaction::Transaction};
use spl_associated_token_account::{
    get_associated_token_address, get_associated_token_address_with_program_id,
};

// Creates a purchase bond transaction that can be sent to solana

// The user_wallet will have already needed to complete the KYC process for the transaction to be successful.
// See [API Reference](https://docs.etherfuse.com/api-reference/onboarding/generate-onboarding-url) for more information.


let client = RpcClient::new(rpc_url);
// Some user wallet keypair
let user_wallet = Keypair::from_str("user_wallet").unwrap();
// Some mint account
let mint = Pubkey::from_str("mint").unwrap();
// Get an un-signed transaction
let tx = make_purchase_bond_instruction(1000000, user_wallet, client, mint).await?;
// Sign the transaction with the users keypair and then...
// Submit the transaction
let sig = client.send_and_confirm_transaction(&tx).await?;

pub async fn make_purchase_bond_transaction(
    client: &RpcClient,
    amount: u64,
    user_wallet: Pubkey,
    mint: Pubkey,
) -> Result<Transaction> {
    let ix_args = PurchaseBondV2InstructionArgs { amount };
    let addresses = generate_buy_addresses(client, mint, user_wallet).await?;
    let mint_auth_multisig_account = get_bond_mint_auth_multisig_if_needed(&client, mint).await?;
    let ix = PurchaseBondV2 {
        kyc_account: addresses.kyc_account,
        user_wallet: user_wallet,
        user_token_account: addresses.user_token_account,
        user_payment_token_account: addresses.user_payment_token_account,
        payment_account: addresses.payment_account,
        payment_token_account: addresses.payment_token_account,
        payment_mint_account: addresses.payment_mint_account,
        payment_feed_account: addresses.payment_feed_account,
        payment_base_price_feed_account: addresses.payment_price_feed_account,
        payment_quote_price_feed_account: addresses.payment_quote_price_feed_account,
        mint_auth_multisig_account,
        bond_account: addresses.bond_account,
        issuance_account: addresses.issuance_account,
        mint_account: mint,
        token2022_program: addresses.token_2022_program,
        associated_token_program: addresses.associated_token_program,
        token_program: addresses.token_program,
        system_program: addresses.system_program,
    }
    .instruction(ix_args);

    let tx = Transaction::new_unsigned(Message::new(&[ix], Some(&user_wallet)));

    Ok(tx)
}

// Creates a transaction to begin the bond redemption process


let client = RpcClient::new(rpc_url);
// Some user wallet keypair
let user_wallet = Keypair::from_str("user_wallet").unwrap();
// Some mint account
let mint = Pubkey::from_str("mint").unwrap();
// Some NFT mint account
let nft_mint = Pubkey::from_str("nft_mint").unwrap();
// Get an un-signed transaction
let tx = make_request_redemption_instruction(1000000, user_wallet, mint, nft_mint)?;
// Sign the transaction with the users keypair and then...
// Submit the transaction
let sig = client.send_and_confirm_transaction(&tx).await?;

pub async fn make_request_redemption_transaction(
    client: &RpcClient,
    amount_in_tokens: u64,
    user_wallet: Pubkey,
    mint: Pubkey,
) -> Result<Transaction> {
    let ix_args = RequestRedemptionV2InstructionArgs {
        amount: amount_in_tokens,
    };
    let addresses = generate_buy_addresses(client, mint, user_wallet).await?;
    let nft_mint_pair = Keypair::new();
    let nft_mint = nft_mint_pair.pubkey();
    let nft_issuance_vault_account = find_nft_issuance_vault_pda(nft_mint).0;
    let nft_issuance_vault_token_account = get_associated_token_address_with_program_id(
        &nft_issuance_vault_account,
        &mint,
        &spl_token_2022::id(),
    );
    let user_nft_token_account = get_associated_token_address(&user_wallet, &nft_mint);
    let nft_metadata_account = Metadata::find_pda(&nft_mint).0;
    let nft_master_edition_account = MasterEdition::find_pda(&nft_mint).0;
    let nft_collection_mint = find_config_pda().0;

    let nft_collection_metadata_account = Metadata::find_pda(&nft_collection_mint).0;
    let nft_collection_master_edition_account = MasterEdition::find_pda(&nft_collection_mint).0;

    let ix = RequestRedemptionV2 {
        kyc_account: find_kyc_pda(user_wallet).0,
        user_wallet,
        config_account: find_config_pda().0,
        token2022_program: addresses.token_2022_program,
        associated_token_program: addresses.associated_token_program,
        token_program: addresses.token_program,
        system_program: addresses.system_program,
        metadata_program: mpl_token_metadata::ID,
        sysvar_instructions: solana_sdk::sysvar::instructions::id(),
        bond_account: addresses.bond_account,
        issuance_account: addresses.issuance_account,
        mint_account: mint,
        user_token_account: addresses.user_token_account,
        nft_mint_account: nft_mint,
        nft_issuance_vault_account,
        nft_issuance_vault_token_account,
        user_nft_token_account,
        nft_metadata_account,
        nft_master_edition_account,
        nft_collection_mint,
        nft_collection_metadata_account,
        nft_collection_master_edition_account,
    }
    .instruction(ix_args);

    Ok(Transaction::new_unsigned(Message::new(
        &[ix],
        Some(&user_wallet),
    )))
}

// Creates a transaction to redeem a bond once payout is available


let client = RpcClient::new(rpc_url);
// Some user wallet keypair
let user_wallet = Keypair::from_str("user_wallet").unwrap();
// The mint for the bond underlying the NFT
let mint = Pubkey::from_str("mint").unwrap();
// The addres of the NFT
let nft_mint = Pubkey::from_str("nft_mint").unwrap();
// Get an un-signed transaction
let tx = make_redeem_bond_transaction(client, user_wallet, mint, nft_mint).await?;
// Sign the transaction with the users keypair and then...
// Submit the transaction
let sig = client.send_and_confirm_transaction(&tx).await?;

pub async fn make_redeem_bond_transaction(
    client: &RpcClient,
    user_wallet: Pubkey,
    mint: Pubkey,
    nft_mint: Pubkey,
) -> Result<Transaction> {
    let bond_account = find_bond_pda(mint).0;
    let data = client.get_account_data(&bond_account).await?;
    let bond = Bond::from_bytes(&data).unwrap();
    let payment_feed_account = find_payment_feed_pda(bond.payment_feed_type).0;
    let issuance_account = find_issuance_pda(bond_account, bond.issuance_number).0;
    let payment_mint_account = find_payment_pda(issuance_account).0;
    let nft_issuance_vault_account = find_nft_issuance_vault_pda(nft_mint).0;
    let nft_issuance_vault_token_account = get_associated_token_address_with_program_id(
        &nft_issuance_vault_account,
        &mint,
        &spl_token_2022::id(),
    );
    let user_nft_token_account = get_associated_token_address(&user_wallet, &nft_mint);
    let user_payment_token_account =
        get_associated_token_address(&user_wallet, &payment_mint_account);
    let nft_metadata_account = Metadata::find_pda(&nft_mint).0;
    let nft_master_edition_account = MasterEdition::find_pda(&nft_mint).0;
    let nft_collection_metadata_account = Metadata::find_pda(&nft_mint).0;
    let payout_account = find_payout_pda(issuance_account).0;
    let payout_token_account = get_associated_token_address(&payout_account, &mint);
    let token2022_program = spl_token_2022::id();
    let associated_token_program = spl_associated_token_account::id();
    let token_program = spl_token::id();
    let metadata_program = mpl_token_metadata::ID;
    let system_program = system_program::id();
    let ix = RedeemBond {
        bond_account,
        mint_account: mint,
        issuance_account,
        user_wallet,
        user_nft_token_account,
        user_payment_token_account,
        payment_mint_account,
        payment_feed_account,
        nft_mint_account: nft_mint,
        nft_metadata_account,
        nft_master_edition_account,
        nft_collection_metadata_account,
        nft_issuance_vault_account,
        nft_issuance_vault_token_account,
        payout_account,
        payout_token_account,
        token2022_program,
        associated_token_program,
        token_program,
        metadata_program,
        system_program,
    }
    .instruction();

    Ok(Transaction::new_unsigned(Message::new(
        &[ix],
        Some(&user_wallet),
    )))
}

// Creates a transaction to redeem a purchase order


let client = RpcClient::new(rpc_url);
// Some user wallet keypair
let user_wallet = Keypair::from_str("user_wallet").unwrap();
// The mint for the bond underlying the NFT
let mint = Pubkey::from_str("mint").unwrap();
// The address of the NFT
let nft_mint = Pubkey::from_str("nft_mint").unwrap();
// Get an un-signed transaction
let tx = make_redeem_purchase_order_transaction(client, user_wallet, mint, nft_mint).await?;
// Sign the transaction with the users keypair and then...
// Submit the transaction
let sig = client.send_and_confirm_transaction(&tx).await?;

pub async fn make_redeem_purchase_order_transaction(
    client: &RpcClient,
    user_wallet: Pubkey,
    mint: Pubkey,
    nft_mint: Pubkey,
) -> Result<Transaction> {
    let mint_auth_multisig_account = get_bond_mint_auth_multisig_if_needed(&client, mint).await?;
    let bond_account = find_bond_pda(mint).0;
    let data = client.get_account_data(&bond_account).await?;
    let bond = Bond::from_bytes(&data).unwrap();
    let issuance_account = find_issuance_pda(bond_account, bond.issuance_number).0;
    let purchase_order_vault_account = find_purchase_order_pda(nft_mint).0;
    let user_token_account =
        get_associated_token_address_with_program_id(&user_wallet, &mint, &spl_token_2022::id());
    let user_nft_token_account = get_associated_token_address(&user_wallet, &nft_mint);
    let nft_metadata_account = Metadata::find_pda(&nft_mint).0;
    let nft_master_edition_account = MasterEdition::find_pda(&nft_mint).0;
    let nft_collection_metadata_account = Metadata::find_pda(&nft_mint).0;
    let token2022_program = spl_token_2022::id();
    let associated_token_program = spl_associated_token_account::id();
    let token_program = spl_token::id();
    let metadata_program = mpl_token_metadata::ID;
    let system_program = system_program::id();

    let ix = RedeemPurchaseOrder {
        user_wallet,
        bond_account,
        mint_account: mint,
        issuance_account,
        purchase_order_vault_account,
        user_token_account,
        user_nft_token_account,
        nft_mint_account: nft_mint,
        nft_metadata_account,
        nft_master_edition_account,
        nft_collection_metadata_account,
        token2022_program,
        token_program,
        associated_token_program,
        metadata_program,
        system_program,
        mint_auth_multisig_account,
    }
    .instruction();

    Ok(Transaction::new_unsigned(Message::new(
        &[ix],
        Some(&user_wallet),
    )))
}

// Create a purchase order.

// The user will need to have already completed the KYC process for the transaction to be successful.
// See [API Reference](https://docs.etherfuse.com/api-reference/onboarding/generate-onboarding-url) for more information.


let client = RpcClient::new(rpc_url);
// Some user wallet keypair
let user_wallet = Keypair::from_str("user_wallet").unwrap();
// The mint for the bond underlying the NFT
let mint = Pubkey::from_str("mint").unwrap();
// The amount of tokens to purchase
let token_amount = 1000000;
// Get an un-signed transaction
let tx = make_create_purchase_order_transaction(client, token_amount, user_wallet, mint).await?;
// Sign the transaction with the users keypair and then...
// Submit the transaction
let sig = client.send_and_confirm_transaction(&tx).await?;

pub async fn make_create_purchase_order_transaction(
    client: &RpcClient,
    token_amount: u64,
    user_wallet: Pubkey,
    mint: Pubkey,
) -> Result<Transaction> {
    let ix_args = CreatePurchaseOrderV2InstructionArgs {
        amount: token_amount,
    };
    let addresses = generate_buy_addresses(client, mint, user_wallet).await?;
    let nft_mint = Keypair::new();
    let nft_mint_account = nft_mint.pubkey();
    let user_nft_token_account = get_associated_token_address(&user_wallet, &nft_mint_account);
    let nft_master_edition_account = MasterEdition::find_pda(&nft_mint_account).0;
    let purchase_order_vault_account = find_purchase_order_pda(nft_mint_account).0;
    let nft_collection_mint = find_config_pda().0;
    let nft_collection_metadata_account = Metadata::find_pda(&nft_collection_mint).0;
    let nft_collection_master_edition_account = MasterEdition::find_pda(&nft_collection_mint).0;
    let nft_metadata_account = Metadata::find_pda(&nft_mint_account).0;

    let ix = CreatePurchaseOrderV2 {
        kyc_account: find_kyc_pda(user_wallet).0,
        user_wallet,
        bond_account: addresses.bond_account,
        issuance_account: addresses.issuance_account,
        payment_account: addresses.payment_account,
        payment_token_account: addresses.payment_token_account,
        user_payment_token_account: addresses.user_payment_token_account,
        user_nft_token_account,
        nft_mint_account,
        nft_metadata_account,
        nft_master_edition_account,
        purchase_order_vault_account,
        nft_collection_mint,
        nft_collection_metadata_account,
        nft_collection_master_edition_account,
        payment_mint_account: addresses.payment_mint_account,
        payment_feed_account: addresses.payment_feed_account,
        payment_base_price_feed_account: addresses.payment_price_feed_account,
        config_account: find_config_pda().0,
        associated_token_program: spl_associated_token_account::id(),
        token2022_program: spl_token_2022::id(),
        token_program: spl_token::id(),
        system_program: system_program::id(),
        metadata_program: mpl_token_metadata::ID,
        sysvar_instructions: solana_sdk::sysvar::instructions::id(),
        payment_quote_price_feed_account: addresses.payment_quote_price_feed_account,
    }
    .instruction(ix_args);

    Ok(Transaction::new_unsigned(Message::new(
        &[ix],
        Some(&user_wallet),
    )))
}

async fn get_bond_mint_auth_multisig_if_needed(
    rpc_client: &RpcClient,
    mint_account: Pubkey,
) -> Result<Option<Pubkey>> {
    let bond_account = find_bond_pda(mint_account).0;
    let data = rpc_client.get_account_data(&bond_account).await?;
    let bond = Bond::from_bytes(&data).unwrap();

    // Get the mint_auth_multisig_account if is_authority_multisig is true
    let mint_auth_multisig_account = if bond.is_authority_multisig {
        let bond_multisig_meta_account = find_bond_multisig_meta_pda(mint_account).0;
        let bond_multisig_meta_data = rpc_client
            .get_account_data(&bond_multisig_meta_account)
            .await?;
        let bond_multisig_meta = BondMultisigMeta::from_bytes(&bond_multisig_meta_data).unwrap();
        Some(bond_multisig_meta.mint_auth_multisig)
    } else {
        None
    };

    Ok(mint_auth_multisig_account)
}

struct BuyAddresses {
    issuance_account: Pubkey,
    payment_account: Pubkey,
    payment_mint_account: Pubkey,
    payment_token_account: Pubkey,
    user_payment_token_account: Pubkey,
    bond_account: Pubkey,
    payment_price_feed_account: Pubkey,
    payment_quote_price_feed_account: Option<Pubkey>,
    kyc_account: Pubkey,
    payment_feed_account: Pubkey,
    user_token_account: Pubkey,
    token_2022_program: Pubkey,
    associated_token_program: Pubkey,
    token_program: Pubkey,
    system_program: Pubkey,
}

async fn generate_buy_addresses(
    client: &RpcClient,
    mint_account: Pubkey,
    user_wallet: Pubkey,
) -> Result<BuyAddresses> {
    let bond_account = find_bond_pda(mint_account).0;
    let issuance_account = find_issuance_pda(bond_account, 1).0;
    let payment_account = find_payment_pda(issuance_account).0;
    let data = client.get_account_data(&bond_account).await?;
    let bond = Bond::from_bytes(&data).unwrap();
    let payment_feed_account = find_payment_feed_pda(bond.payment_feed_type).0;
    let data = client.get_account_data(&payment_feed_account).await?;
    let payment_feed = PaymentFeed::from_bytes(&data).unwrap();
    let payment_mint_account = payment_feed.payment_mint;
    let mut payment_quote_price_feed_account = None;
    if payment_feed.quote_price_feed != Pubkey::default() {
        payment_quote_price_feed_account = Some(payment_feed.quote_price_feed);
    }
    let user_token_account = get_associated_token_address_with_program_id(
        &user_wallet,
        &mint_account,
        &spl_token_2022::id(),
    );
    let payment_price_feed_account = payment_feed.base_price_feed;
    let kyc_account = find_kyc_pda(user_wallet).0;
    let payment_token_account =
        get_associated_token_address(&payment_account, &payment_mint_account);
    let user_payment_token_account =
        get_associated_token_address(&user_wallet, &payment_mint_account);

    Ok(BuyAddresses {
        issuance_account,
        payment_account,
        payment_mint_account,
        payment_token_account,
        user_payment_token_account,
        bond_account,
        payment_price_feed_account,
        payment_quote_price_feed_account,
        kyc_account,
        payment_feed_account,
        user_token_account,
        token_2022_program: spl_token_2022::id(),
        associated_token_program: spl_associated_token_account::id(),
        token_program: spl_token::id(),
        system_program: system_program::id(),
    })
}

Modules§

accounts
This code was AUTOGENERATED using the kinobi library. Please DO NOT EDIT THIS FILE, instead use visitors to add features, then rerun kinobi to update it.
errors
This code was AUTOGENERATED using the kinobi library. Please DO NOT EDIT THIS FILE, instead use visitors to add features, then rerun kinobi to update it.
types
This code was AUTOGENERATED using the kinobi library. Please DO NOT EDIT THIS FILE, instead use visitors to add features, then rerun kinobi to update it.

Structs§

CreatePurchaseOrderV2
Accounts.
CreatePurchaseOrderV2Builder
Instruction builder for CreatePurchaseOrderV2.
CreatePurchaseOrderV2InstructionArgs
PurchaseBondV2
Accounts.
PurchaseBondV2Builder
Instruction builder for PurchaseBondV2.
PurchaseBondV2InstructionArgs
RedeemBond
Accounts.
RedeemBondBuilder
Instruction builder for RedeemBond.
RedeemPurchaseOrder
Accounts.
RedeemPurchaseOrderBuilder
Instruction builder for RedeemPurchaseOrder.
RequestRedemptionV2
Accounts.
RequestRedemptionV2Builder
Instruction builder for RequestRedemptionV2.
RequestRedemptionV2InstructionArgs

Constants§

ID
stablebond program ID.
PROGRAM_OWNER
PYTH_PROGRAM
PYTH_USDC
STABLEBOND_ID
stablebond program ID.

Functions§

find_access_pass_pda
find_bond_multisig_meta_pda
find_bond_pda
find_config_pda
find_delegate_pda
find_issuance_pda
find_kyc_pda
find_nft_issuance_vault_pda
find_offramp_pda
find_onramp_pda
find_payment_feed_pda
find_payment_pda
find_payout_pda
find_purchase_order_pda
find_sell_liquidity_pda