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§
- Create
Purchase Order V2 - Accounts.
- Create
Purchase Order V2Builder - Instruction builder for
CreatePurchaseOrderV2. - Create
Purchase Order V2Instruction Args - Purchase
Bond V2 - Accounts.
- Purchase
Bond V2Builder - Instruction builder for
PurchaseBondV2. - Purchase
Bond V2Instruction Args - Redeem
Bond - Accounts.
- Redeem
Bond Builder - Instruction builder for
RedeemBond. - Redeem
Purchase Order - Accounts.
- Redeem
Purchase Order Builder - Instruction builder for
RedeemPurchaseOrder. - Request
Redemption V2 - Accounts.
- Request
Redemption V2Builder - Instruction builder for
RequestRedemptionV2. - Request
Redemption V2Instruction Args
Constants§
- ID
stablebondprogram ID.- PROGRAM_
OWNER - PYTH_
PROGRAM - PYTH_
USDC - STABLEBOND_
ID stablebondprogram ID.