This is an SDK for Stellar that is suitable for use in a Substrate project. It does not depend on the standard library but on the crate sp-std
, which is Substrate's replacement of Rust's standard library.
This crate has two features:
std
: This feature will enable the standard library. It is enabled by default, therefore this crate needs to be imported using default-features = false
in a Substrate projectoffchain
: This is a collection of features usable in an offchain worker, where http requests are possible. It mainly comprises an abstraction layer over parts of the Horizon API.In order to make the SDK API convenient to use with a variety of input types, we make heavy use of conversion traits. For example the type Horizon
implements the method fetch_account
whose first parameter is an account id. This parameter can be provided as a string representing the string encoding of the account id:
rust
horizon.fetch_account("GDGRDTRINPF66FNC47H22NY6BNWMCD5Q4XZTVA2KG7PFZ64WHRIU62TQ", 1000)?;
Since strings in Substrate are usually represented as Vec<u8>
, also a vector representation of this string can be used as an argument:
rust
let vec: Vec<u8> = Vec::from("GDGRDTRINPF66FNC47H22NY6BNWMCD5Q4XZTVA2KG7PFZ64WHRIU62TQ".as_bytes());
horizon.fetch_account(vec, 1000)?;
Also u8
slices and u8
arrays are possible argument types:
rust
let slice: &[u8] = "GDGRDTRINPF66FNC47H22NY6BNWMCD5Q4XZTVA2KG7PFZ64WHRIU62TQ".as_bytes();
let array: [u8; 56] = slice.try_into()?;
horizon.fetch_account(slice, 1000)?;
horizon.fetch_account(array, 1000)?;
It is also possible to provide an AccountId
struct itself:
rust
let account_id = AccountId::("GDGRDTRINPF66FNC47H22NY6BNWMCD5Q4XZTVA2KG7PFZ64WHRIU62TQ")?;
horizon.fetch_account(account_id, 1000)?;
This crate provides the following conversion traits:
IntoAccountId
This is the trait for parameters that represent an AccountId
. It is implemented by
AsRef<[u8]>
such as &str
, [u8; N]
, [u8]
, Vec<u8>
: The string encoding of the account id (using Stellar's encoding of account ids)AccountId
: An AccountId
IntoAmount
This is the trait for parameters that represent an asset amount. This is used to cleanly distinguish between stroop amounts and lumen amounts (where one lumen is 10000000 stroops). It is implemented by
LumenAmount
: A wrapped f64
representing an amount in lumensStroopAmount
: A wrapped i64
representing an amount in stroopsAsRef<[u8]>
such as &str
, [u8; N]
, [u8]
, Vec<u8>
: This is the decimal string of the amount in lumens. The string can have up to 7 decimal places. This representation is usually used in responses of the Horizon APIIt is recommended to use either LumenAmount
or the string representation as they can be converted without loss to Stellar's internal stroop representation of amounts.
IntoClaimbleBalanceId
This is the trait for parameters that represent an ClaimableBalanceId
. It is implemented by
AsBinary
: this can be either the raw binary value (AsBinary::Binary
) of the claimable balance id (36 bytes) or its hex encoding as a string (AsBinary::Hex
)ClaimableBalanceId
: A ClaimableBalanceId
IntoDataValue
This is the trait for parameters that represent an DataValue
. It is implemented by
AsRef<[u8]>
such as &str
, [u8; N]
, [u8]
, Vec<u8>
: The data value stringDataValue
: An DataValue
IntoHash
This is the trait for parameters that represent an Hash
. It is implemented by
AsBinary
: this can be either the raw binary value (AsBinary::Binary
) of the hash (32 bytes) or its hex encoding as a string (AsBinary::Hex
)Hash
: A Hash
IntoMuxedAccountId
This is the trait for parameters that represent a MuxedAccount
. Be aware that the type MuxedAccount
contains simple account ids as well as proper multiplexed account ids. It is implemented by
AsRef<[u8]>
such as &str
, [u8; N]
, [u8]
, Vec<u8>
: The string encoding of the muxed account id (using Stellar's encoding of muxed account ids)AccountId
: A simple AccountId
repesented as a MuxedAccount
MuxedAccount
: An MuxedAccount
IntoPublicKey
This is the trait for parameters that represent a PublicKey
. Be aware that the types AccountId
and PublicKey
are aliases (they are synonyms in Stellar). The trait IntoPublicKey
exists for convenience and to make it more clear when an account id is used as a public key. It is implemented by
AsRef<[u8]>
such as &str
, [u8; N]
, [u8]
, Vec<u8>
: The string encoding of the public key (using Stellar's encoding of public keys)PublicKey
: A PublicKey
(which is an alias for AccountId
)IntoSecretKey
This is the trait for parameters that represent a SecretKey
. It is implemented by
AsRef<[u8]>
such as &str
, [u8; N]
, [u8]
, Vec<u8>
: The string encoding of the secret key (using Stellar's encoding of secret keys)SecretKey
: A SecretKey
IntoTimePoint
This is the trait for parameters that represent a point in time used by transaction time bounds. It is implemented by
MilliSecondEpochTime
: a unix timestamp represented in millisecondsSecondEpochTime
: a unix timestamp represented in seconds()
: for an unlimited time boundThis is one of the main workflows when using this SDK. Note that these features only become available when using the crate feature offchain
. It usually consists of the following steps:
Horizon
type and provide the base url of the horizon server.Operation::new_payment
(for a payment operation) or Operation::new_bump_sequence
(for a bump sequence number operation). The constructors make use of the conversion traits.The following code shows a complete example.
```rust use substratestellarsdk::{ horizon::Horizon, network::TEST_NETWORK, Asset, IntoSecretKey, Memo, MilliSecondEpochTime, MuxedAccount, Operation, Price, PublicKey as StellarPublicKey, SecondEpochTime, StroopAmount, TimeBounds, Transaction, TransactionEnvelope, XdrCodec, };
// ... // in some function:
const ACCOUNTID1: &str = "GDGRDTRINPF66FNC47H22NY6BNWMCD5Q4XZTVA2KG7PFZ64WHRIU62TQ"; const ACCOUNTID2: &str = "GBNKQVTFRP25TIQRODMU5GJGSXDKHCEUDN7LNMOS5PNM427LMR77NV4M"; const ACCOUNT_ID3: &str = "GCACWDM2VEYTXGUI3CUYLBJ453IBEPQ3XEJKA772ARAP5XDQ4NMGFZGJ";
const SIGNER1: &str = "SCVKZEONBSU3XD6OTHXGAP6BTEWHOU4RPZQZJJ5AVAGPXUZ5A4D7MU6S"; const SIGNER3: &str = "SDOKV37I4TI655LMEMDQFOWESJ3LK6DDFKIVTYKN4YYTSAYFIBPP7MYI";
// Step 1: instantiate horizon server let horizon = Horizon::new("https://horizon-testnet.stellar.org");
// Step 2: fetch next sequence number of account let nextsequencenumber = horizon.fetchnextsequencenumber(ACCOUNTID1, 10_000)?;
debug::info!("Sequence number: {}", nextsequencenumber);
// Step 3: build transaction let mut transaction = Transaction::new( ACCOUNTID1, nextsequencenumber, Some(2 * 321), Some(TimeBounds::fromtimepoints( SecondEpochTime(162620000), MilliSecondEpochTime(1667257200000), )), Some(Memo::fromtext_memo("Hello World!")?), )?;
// Step 4: add operations transaction.appendoperation( Operation::newpayment( ACCOUNTID2, Asset::fromassetcode("USD", ACCOUNTID3)?, StroopAmount(1234560000), )? .setsourceaccount(ACCOUNTID3)?, )?;
transaction.appendoperation(Operation::newmanageselloffer( Asset::fromassetcode("DOMINATION", ACCOUNTID2)?, Asset::native(), "152.103", Price::fromfloat(4.58)?, Some(1742764), )?)?;
// Step 5: transform into transaction envelope and sign let mut envelope = transaction.intotransactionenvelope();
// Step 6: sign transaction envelope envelope.sign( &TESTNETWORK, vec![&SIGNER1.intosecretkey()?, &SIGNER3.intosecret_key()?], )?;
// Step 7: submit transaction let submissionresponse = horizon.submittransaction(&envelope, 60000, true); debug::info!("Response: {:?}", submissionresponse); ```