Skip to content

Commit

Permalink
Revert "Remove token deploy in anticipation of removal of the soroban…
Browse files Browse the repository at this point in the history
… only built-in token (stellar#798)"

This reverts commit 62a2030.
  • Loading branch information
sisuresh committed Dec 15, 2022
1 parent 62a2030 commit 50d98f1
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 34 deletions.
12 changes: 12 additions & 0 deletions soroban-sdk/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ impl DeployerWithCurrentContract {
);
unsafe { BytesN::<32>::unchecked_new(env.clone(), id) }
}

/// Deploy a built-in token contract.
///
/// The contract ID from the currently executing contract and the given salt
/// will be used to derive a contract ID for the deployed contract.
///
/// Returns the deployed contract's ID.
pub fn deploy_token(&self) -> BytesN<32> {
let env = &self.env;
let id = env.create_token_from_contract(self.salt.to_object());
unsafe { BytesN::<32>::unchecked_new(env.clone(), id) }
}
}

#[doc(hidden)]
Expand Down
42 changes: 30 additions & 12 deletions soroban-sdk/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,18 +438,36 @@ impl Env {
)
}

/// Register the built-in Stellar Asset Contract for testing.
pub fn register_stellar_asset_contract(&self, asset: xdr::Asset) -> BytesN<32> {
let create = xdr::HostFunction::CreateContract(xdr::CreateContractArgs {
contract_id: xdr::ContractId::Asset(asset),
source: xdr::ScContractCode::Token,
});

self.env_impl
.invoke_function(create)
.unwrap()
.try_into_val(self)
.unwrap()
/// Register the built-in token contract with the [Env] for testing.
///
/// Passing a contract ID for the first arguments registers the contract
/// with that contract ID. Providing `None` causes a random ID to be
/// assigned to the contract.
///
/// Registering a contract that is already registered replaces it.
///
/// Returns the contract ID of the registered contract.
///
/// ### Examples
/// ```
/// use soroban_sdk::{BytesN, Env};
///
/// #[test]
/// fn test() {
/// # }
/// # fn main() {
/// let env = Env::default();
/// env.register_contract_token(None);
/// }
/// ```
pub fn register_contract_token<'a>(
&self,
contract_id: impl Into<Option<&'a BytesN<32>>>,
) -> BytesN<32> {
self.register_contract_with_optional_contract_id_and_source(
contract_id,
xdr::ScContractCode::Token,
)
}

fn register_contract_with_optional_contract_id_and_source<'a>(
Expand Down
1 change: 1 addition & 0 deletions soroban-sdk/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ mod contractfile_with_sha256;
mod contractimport;
mod contractimport_with_error;
mod contractimport_with_sha256;
mod contracttoken;
85 changes: 85 additions & 0 deletions soroban-sdk/src/tests/contracttoken.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use crate as soroban_sdk;
use soroban_sdk::{
contractclient, contracttype, testutils::AccountId as _, AccountId, Bytes, BytesN, Env,
};

#[contractclient(name = "TokenClient")]
pub trait Token {
fn init(env: Env, admin: Identifier, metadata: TokenMetadata);
fn name(env: Env) -> Bytes;
}

#[derive(Clone)]
#[contracttype]
pub enum Identifier {
Account(AccountId),
}

#[derive(Clone)]
#[contracttype]
pub struct TokenMetadata {
pub name: Bytes,
pub symbol: Bytes,
pub decimals: u32,
}

#[test]
fn test_register_token() {
let e = Env::default();

let contract_id = e.register_contract_token(None);
let client = TokenClient::new(&e, &contract_id);

client.init(
&Identifier::Account(AccountId::random(&e)),
&TokenMetadata {
name: Bytes::from_slice(&e, b"testme"),
decimals: 7,
symbol: Bytes::from_slice(&e, &[]),
},
);

assert_eq!(client.name(), Bytes::from_slice(&e, b"testme"))
}

#[test]
fn test_register_token_at_id() {
let e = Env::default();

let contract_id = BytesN::from_array(&e, &[1; 32]);
e.register_contract_token(&contract_id);
let client = TokenClient::new(&e, &contract_id);

client.init(
&Identifier::Account(AccountId::random(&e)),
&TokenMetadata {
name: Bytes::from_slice(&e, b"testme"),
decimals: 7,
symbol: Bytes::from_slice(&e, &[]),
},
);

assert_eq!(client.name(), Bytes::from_slice(&e, b"testme"))
}

#[test]
fn test_reregister_over_wasm_with_token() {
let e = Env::default();

// Register a contract with bogus wasm.
let contract_id = e.register_contract_wasm(None, &[]);
// Reregister the contract with a token instead.
e.register_contract_token(&contract_id);
let client = TokenClient::new(&e, &contract_id);

client.init(
&Identifier::Account(AccountId::random(&e)),
&TokenMetadata {
name: Bytes::from_slice(&e, b"testme"),
decimals: 7,
symbol: Bytes::from_slice(&e, &[]),
},
);

assert_eq!(client.name(), Bytes::from_slice(&e, b"testme"))
}
2 changes: 1 addition & 1 deletion soroban-sdk/src/xdr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ pub use super::env::xdr::{
};

// XDR for ledger entries.
pub use super::env::xdr::{AccountEntry, AccountId, Asset};
pub use super::env::xdr::{AccountEntry, AccountId};
66 changes: 45 additions & 21 deletions soroban-token-spec/src/tests/use_token_contract.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use soroban_auth::{testutils::ed25519::generate, Identifier, Signature};
use soroban_sdk::{contractimpl, contracttype, BytesN, Env, IntoVal};
use soroban_auth::{
testutils::ed25519::{generate, sign},
Identifier, Signature,
};
use soroban_sdk::{contractimpl, contracttype, symbol, BytesN, Env, IntoVal};

mod token_contract {
soroban_sdk::contractimport!(
Expand All @@ -8,13 +11,17 @@ mod token_contract {
pub type TokenClient = Client;
}

use token_contract::TokenClient;
use token_contract::{TokenClient, TokenMetadata};

#[contracttype]
pub enum DataKey {
Token,
}

fn get_contract_id(e: &Env) -> Identifier {
Identifier::Contract(e.get_current_contract().into())
}

fn get_token(e: &Env) -> BytesN<32> {
e.storage().get_unchecked(DataKey::Token).unwrap()
}
Expand All @@ -23,45 +30,62 @@ pub struct TestContract;

#[contractimpl]
impl TestContract {
pub fn init(e: Env, contract: BytesN<32>) {
e.storage().set(DataKey::Token, contract);
pub fn init(e: Env, salt: BytesN<32>) {
let id = e.deployer().with_current_contract(salt).deploy_token();
let metadata = TokenMetadata {
name: "name".into_val(&e),
symbol: "symbol".into_val(&e),
decimals: 7u32,
};
TokenClient::new(&e, &id).init(&get_contract_id(&e), &metadata);

e.storage().set(DataKey::Token, id);
}

pub fn get_token(e: Env) -> BytesN<32> {
get_token(&e)
}

pub fn approve(e: Env, spender: Identifier, amount: i128) {
TokenClient::new(&e, get_token(&e)).approve(&Signature::Invoker, &0, &spender, &amount);
pub fn mint(e: Env, to: Identifier, amount: i128) {
TokenClient::new(&e, get_token(&e)).mint(&Signature::Invoker, &0, &to, &amount);
}

pub fn allowance(e: Env, from: Identifier, spender: Identifier) -> i128 {
TokenClient::new(&e, get_token(&e)).allowance(&from, &spender)
pub fn set_admin(e: Env, new_admin: Identifier) {
TokenClient::new(&e, get_token(&e)).set_admin(&Signature::Invoker, &0, &new_admin);
}
}

#[test]
fn test() {
use soroban_sdk::xdr::Asset;

let env = Env::default();

let token_contract_id = env.register_stellar_asset_contract(Asset::Native);

let contract_id = BytesN::from_array(&env, &[0; 32]);
env.register_contract(&contract_id, TestContract);
let client = TestContractClient::new(&env, &contract_id);
client.init(&token_contract_id);

let salt = BytesN::from_array(&env, &[1; 32]);
client.init(&salt);

let token_client = TokenClient::new(&env, &client.get_token());
assert_eq!(token_client.name(), "native".into_val(&env));
assert_eq!(token_client.name(), "name".into_val(&env));

let (id, _signer) = generate(&env);
let (id, signer) = generate(&env);
let (id2, _signer2) = generate(&env);

let amount = 10;
client.approve(&id, &amount);
assert_eq!(
client.allowance(&Identifier::Contract(contract_id), &id),
amount
client.mint(&id, &amount);
assert_eq!(token_client.balance(&id), amount);

// transger admin so we can test ed25519 auth
client.set_admin(&id);

let nonce = &token_client.nonce(&id);
let sig = sign(
&env,
&signer,
&client.get_token(),
symbol!("mint"),
(&id, nonce, &id2, &amount),
);
token_client.mint(&sig, nonce, &id2, &amount);
assert_eq!(token_client.balance(&id2), amount);
}

0 comments on commit 50d98f1

Please sign in to comment.