-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5f367ed
commit 91fed12
Showing
5 changed files
with
291 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use clap::Subcommand; | ||
use stellar_xdr::cli as xdr; | ||
|
||
pub mod token; | ||
|
||
#[derive(Debug, Subcommand)] | ||
pub enum Cmd { | ||
/// Wrap, create, and manage token contracts | ||
Token(token::Root), | ||
|
||
/// Decode xdr | ||
Xdr(xdr::Root), | ||
} | ||
|
||
#[derive(thiserror::Error, Debug)] | ||
pub enum Error { | ||
#[error(transparent)] | ||
Token(#[from] token::Error), | ||
#[error(transparent)] | ||
Xdr(#[from] xdr::Error), | ||
} | ||
|
||
impl Cmd { | ||
pub async fn run(&self) -> Result<(), Error> { | ||
match &self { | ||
Cmd::Token(token) => token.run().await?, | ||
Cmd::Xdr(xdr) => xdr.run()?, | ||
} | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
use std::fmt::Debug; | ||
|
||
use crate::commands::contract::{deploy, id}; | ||
use clap::{Parser, Subcommand}; | ||
|
||
#[derive(Parser, Debug)] | ||
pub struct Root { | ||
#[clap(subcommand)] | ||
cmd: Cmd, | ||
} | ||
|
||
#[derive(Subcommand, Debug)] | ||
enum Cmd { | ||
/// Deploy a token contract to wrap an existing Stellar classic asset for smart contract usage | ||
/// Deprecated, use `soroban contract deploy asset` instead | ||
Wrap(deploy::asset::Cmd), | ||
/// Compute the expected contract id for the given asset | ||
/// Deprecated, use `soroban contract id asset` instead | ||
Id(id::asset::Cmd), | ||
} | ||
|
||
#[derive(thiserror::Error, Debug)] | ||
pub enum Error { | ||
#[error(transparent)] | ||
Wrap(#[from] deploy::asset::Error), | ||
#[error(transparent)] | ||
Id(#[from] id::asset::Error), | ||
} | ||
|
||
impl Root { | ||
pub async fn run(&self) -> Result<(), Error> { | ||
match &self.cmd { | ||
Cmd::Wrap(wrap) => wrap.run().await?, | ||
Cmd::Id(id) => id.run()?, | ||
} | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ pub mod fee; | |
pub mod key; | ||
pub mod log; | ||
pub mod toid; | ||
pub mod txn; | ||
pub mod utils; | ||
pub mod wasm; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
//! This module contains a transaction builder for Stellar. | ||
//! | ||
use soroban_env_host::xdr::{self, Operation, Transaction, Uint256, VecM}; | ||
|
||
|
||
#[derive(thiserror::Error, Debug)] | ||
pub enum Error { | ||
#[error("")] | ||
InvokeHostFunctionOpMustBeOnlyOperation, | ||
#[error(transparent)] | ||
Xdr(#[from] xdr::Error), | ||
#[error("invalid source account strkey type")] | ||
InvalidSourceAccountStrkeyType, | ||
} | ||
|
||
fn to_muxed_account(source_account: stellar_strkey::Strkey) -> Result<xdr::MuxedAccount, Error> { | ||
let raw_bytes = match source_account { | ||
stellar_strkey::Strkey::PublicKeyEd25519(x) => x.0, | ||
stellar_strkey::Strkey::MuxedAccountEd25519(x) => x.ed25519, | ||
_ => return Err(Error::InvalidSourceAccountStrkeyType), | ||
}; | ||
Ok(xdr::MuxedAccount::Ed25519(xdr::Uint256(raw_bytes))) | ||
} | ||
|
||
pub struct TransactionBuilder { | ||
pub txn: Transaction, | ||
} | ||
|
||
impl TransactionBuilder { | ||
pub fn new(source_account: stellar_strkey::Strkey) -> Result<Self, Error> { | ||
let source_account = to_muxed_account(source_account)?; | ||
Ok(Self { | ||
txn: Transaction { | ||
source_account, | ||
fee: 100, | ||
operations: VecM::default(), | ||
seq_num: xdr::SequenceNumber(0), | ||
cond: xdr::Preconditions::None, | ||
memo: xdr::Memo::None, | ||
ext: xdr::TransactionExt::V0, | ||
}, | ||
}) | ||
} | ||
|
||
pub fn set_source_account(&mut self, source_account: stellar_strkey::Strkey) -> Result<&mut Self, Error> { | ||
self.txn.source_account = to_muxed_account(source_account)?; | ||
Ok(self) | ||
} | ||
|
||
pub fn set_fee(&mut self, fee: u32) -> &mut Self { | ||
self.txn.fee = fee; | ||
self | ||
} | ||
|
||
pub fn set_sequence_number(&mut self, sequence_number: i64) -> &mut Self { | ||
self.txn.seq_num = xdr::SequenceNumber(sequence_number); | ||
self | ||
} | ||
|
||
pub fn add_operation(&mut self, operation: Operation) -> Result<&mut Self, Error> { | ||
if !self.txn.operations.is_empty() | ||
&& matches!( | ||
operation, | ||
Operation { | ||
body: xdr::OperationBody::InvokeHostFunction(_), | ||
.. | ||
} | ||
) | ||
{ | ||
return Err(Error::InvokeHostFunctionOpMustBeOnlyOperation); | ||
} | ||
self.txn.operations.push(operation); | ||
Ok(self) | ||
} | ||
|
||
pub fn cond(&mut self, cond: xdr::Preconditions) -> &mut Self { | ||
self.txn.cond = cond; | ||
self | ||
} | ||
|
||
pub fn build(&self) -> Transaction { | ||
self.txn.clone() | ||
} | ||
} | ||
|
||
pub struct OperationBuilder { | ||
op: Operation, | ||
} | ||
|
||
impl OperationBuilder { | ||
pub fn new() -> Self { | ||
Self { | ||
op: Operation { | ||
source_account: None, | ||
body: xdr::OperationBody::Inflation, | ||
}, | ||
} | ||
} | ||
|
||
pub fn set_source_account(&mut self, source_account: stellar_strkey::Strkey) -> Result<&mut Self, Error> { | ||
self.op.source_account = Some(to_muxed_account(source_account)?); | ||
Ok(self) | ||
} | ||
|
||
pub fn set_body(&mut self, body: xdr::OperationBody) -> &mut Self { | ||
self.op.body = body; | ||
self | ||
} | ||
|
||
pub fn set_host_function(&mut self, host_function: xdr::HostFunction) -> &mut Self { | ||
if let xdr::OperationBody::InvokeHostFunction(ref mut op) = self.op.body { | ||
op.host_function = host_function; | ||
} | ||
self | ||
} | ||
|
||
pub fn set_auth(&mut self, auth: VecM<u8>) -> &mut Self { | ||
if let xdr::OperationBody::InvokeHostFunction(ref mut op) = self.op.body { | ||
op.auth = auth; | ||
} | ||
self | ||
} | ||
|
||
pub fn build(&self) -> Operation { | ||
self.op.clone() | ||
} | ||
} | ||
|
||
pub struct OperationBodyBuilder { | ||
body: xdr::OperationBody, | ||
} | ||
|
||
impl OperationBodyBuilder { | ||
pub fn new() -> Self { | ||
Self { | ||
body: xdr::OperationBody::Inflation, | ||
} | ||
} | ||
|
||
pub fn set_invoke_host_function(&mut self, invoke_host_function: xdr::InvokeHostFunctionOp) -> &mut Self { | ||
self.body = xdr::OperationBody::InvokeHostFunction(invoke_host_function); | ||
self | ||
} | ||
|
||
pub fn build(&self) -> xdr::OperationBody { | ||
self.body.clone() | ||
} | ||
} | ||
|
||
pub struct InvokeHostFunctionOpBuilder(xdr::HostFunction, Vec<xdr::SorobanAuthorizationEntry>); | ||
|
||
impl InvokeHostFunctionOpBuilder { | ||
fn new(host_function: xdr::HostFunction) -> Self { | ||
Self(host_function, vec![]) | ||
} | ||
pub fn upload(wasm: &[u8]) -> Result<Self, Error> { | ||
Ok(Self::new(xdr::HostFunction::UploadContractWasm( | ||
wasm.try_into()?, | ||
))) | ||
} | ||
|
||
pub fn create_contract( | ||
source_account: stellar_strkey::Strkey, | ||
salt: [u8; 32], | ||
wasm_hash: xdr::Hash, | ||
) -> Result<Self, Error> { | ||
let stellar_strkey::Strkey::PublicKeyEd25519(bytes) = source_account else { | ||
panic!("Invalid public key"); | ||
}; | ||
|
||
let contract_id_preimage = | ||
xdr::ContractIdPreimage::Address(xdr::ContractIdPreimageFromAddress { | ||
address: xdr::ScAddress::Account(xdr::AccountId( | ||
xdr::PublicKey::PublicKeyTypeEd25519(bytes.0.into()), | ||
)), | ||
salt: Uint256(salt), | ||
}); | ||
|
||
Ok(Self::new(xdr::HostFunction::CreateContract( | ||
xdr::CreateContractArgs { | ||
contract_id_preimage, | ||
executable: xdr::ContractExecutable::Wasm(wasm_hash), | ||
}, | ||
))) | ||
} | ||
|
||
pub fn add_auth(&mut self, auth: xdr::SorobanAuthorizationEntry) -> &mut Self { | ||
self.1.push(auth); | ||
self | ||
} | ||
|
||
pub fn build(self) -> Result<xdr::OperationBody, Error> { | ||
Ok(xdr::OperationBody::InvokeHostFunction( | ||
xdr::InvokeHostFunctionOp { | ||
host_function: self.0, | ||
auth: self.1.try_into()?, | ||
}, | ||
)) | ||
} | ||
} |