Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions apps/smart-contracts/contracts/deployer/src/deployer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ pub struct DeployAllParams {
pub vault_salt: BytesN<32>,
pub token_name: String,
pub token_symbol: String,
pub escrow_id: String,
pub decimal: u32,
pub escrow_contract: Address,
pub vault_admin: Address,
Expand Down Expand Up @@ -75,15 +74,15 @@ impl DeployerContract {
/// * `salt` - Unique salt for deterministic address derivation
/// * `name` - Token name
/// * `symbol` - Token symbol
/// * `escrow_id` - Escrow contract ID (immutable after init)
/// * `escrow_contract` - Escrow contract address (immutable after init)
/// * `decimal` - Token decimals (max 18)
/// * `mint_authority` - Address authorized to mint tokens
pub fn deploy_participation_token(
env: Env,
salt: BytesN<32>,
name: String,
symbol: String,
escrow_id: String,
escrow_contract: Address,
decimal: u32,
mint_authority: Address,
) -> Address {
Expand All @@ -99,7 +98,7 @@ impl DeployerContract {
let constructor_args: Vec<Val> = (
name,
symbol,
escrow_id,
escrow_contract,
decimal,
mint_authority,
)
Expand Down Expand Up @@ -202,6 +201,10 @@ impl DeployerContract {
/// 4. Transfer token-sale admin to params.token_sale_admin via `set_admin`
/// 5. Deploy vault-contract pointing to the participation-token
pub fn deploy_all(env: Env, signer: Address, params: DeployAllParams) -> DeployedContracts {
let admin: Address = env.storage().instance().get(&DataKey::Admin).unwrap();
if signer != admin {
panic!("Signer must be the contract admin");
}
signer.require_auth();

let participation_token_wasm: BytesN<32> = env
Expand All @@ -225,7 +228,7 @@ impl DeployerContract {
// Step 1: Deploy token-sale with deployer as temporary admin
// (allows deployer to call set_token and set_admin in steps 3-4)
let token_sale_args: Vec<Val> = (
params.escrow_contract,
params.escrow_contract.clone(),
deployer_addr.clone(),
params.hard_cap,
params.max_per_investor,
Expand All @@ -240,7 +243,7 @@ impl DeployerContract {
let participation_token_args: Vec<Val> = (
params.token_name,
params.token_symbol,
params.escrow_id,
params.escrow_contract,
params.decimal,
token_sale_addr.clone(),
)
Expand Down
43 changes: 41 additions & 2 deletions apps/smart-contracts/contracts/deployer/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ fn test_deploy_participation_token() {
let deployer = setup_deployer(&env, &admin);

let salt = BytesN::from_array(&env, &[1u8; 32]);
let escrow_contract = Address::generate(&env);

let token_addr = deployer.deploy_participation_token(
&salt,
&String::from_str(&env, "TestToken"),
&String::from_str(&env, "TST"),
&String::from_str(&env, "escrow-001"),
&escrow_contract,
&7u32,
&mint_authority,
);
Expand Down Expand Up @@ -130,7 +131,6 @@ fn test_deploy_all() {
vault_salt,
token_name: String::from_str(&env, "CampaignToken"),
token_symbol: String::from_str(&env, "CAMP"),
escrow_id: String::from_str(&env, "escrow-001"),
decimal: 7u32,
escrow_contract,
vault_admin,
Expand All @@ -149,6 +149,45 @@ fn test_deploy_all() {
assert_ne!(result.token_sale, result.vault_contract);
}

#[test]
#[should_panic(expected = "Signer must be the contract admin")]
fn test_deploy_all_rejects_non_admin_signer() {
let env = Env::default();
env.mock_all_auths();

let admin = Address::generate(&env);
let non_admin = Address::generate(&env);
let escrow_contract = Address::generate(&env);
let vault_admin = Address::generate(&env);
let token_sale_admin = Address::generate(&env);
let usdc = Address::generate(&env);
let deployer = setup_deployer(&env, &admin);

let token_sale_salt = BytesN::from_array(&env, &[10u8; 32]);
let participation_salt = BytesN::from_array(&env, &[11u8; 32]);
let vault_salt = BytesN::from_array(&env, &[12u8; 32]);

deployer.deploy_all(
&non_admin,
&DeployAllParams {
participation_salt,
token_sale_salt,
vault_salt,
token_name: String::from_str(&env, "CampaignToken"),
token_symbol: String::from_str(&env, "CAMP"),
decimal: 7u32,
escrow_contract,
vault_admin,
vault_enabled: true,
roi_percentage: 5i128,
usdc,
token_sale_admin,
hard_cap: 1_000_000i128,
max_per_investor: 10_000i128,
}
);
}

#[test]
fn test_update_wasm() {
let env = Env::default();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
use crate::allowance::{read_allowance, spend_allowance, write_allowance};
use crate::balance::{read_balance, receive_balance, spend_balance};
use crate::metadata::{
read_decimal, read_escrow_id, read_mint_authority, read_name, read_symbol,
write_escrow_id, write_mint_authority, write_metadata,
read_decimal, read_escrow_contract, read_mint_authority, read_name, read_symbol,
write_escrow_contract, write_mint_authority, write_metadata,
};
use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD};
use soroban_sdk::{
Expand All @@ -32,14 +32,14 @@ impl Token {
/// # Arguments
/// * `name` - Token name
/// * `symbol` - Token symbol
/// * `escrow_id` - Escrow contract ID (as String)
/// * `escrow_contract` - Escrow contract address
/// * `decimal` - Token decimals (default: 7, max: 18)
/// * `mint_authority` - Address authorized to mint tokens (Participation Token contract)
pub fn __constructor(
e: Env,
name: String,
symbol: String,
escrow_id: String,
escrow_contract: Address,
decimal: u32,
mint_authority: Address,
) {
Expand All @@ -57,9 +57,9 @@ impl Token {
},
);

// Write immutable metadata (escrow_id, mint_authority)
// Write immutable metadata (escrow_contract, mint_authority)
// These functions will panic if called twice (immutability enforced)
write_escrow_id(&e, &escrow_id);
write_escrow_contract(&e, &escrow_contract);
write_mint_authority(&e, &mint_authority);
}

Expand Down Expand Up @@ -202,13 +202,13 @@ impl TokenInterface for Token {
// Additional getters for T-REX-aligned metadata
#[contractimpl]
impl Token {
/// Get the escrow contract ID associated with this token.
/// Get the escrow contract address associated with this token.
/// This is immutable metadata set at initialization.
pub fn escrow_id(e: Env) -> String {
pub fn escrow_contract(e: Env) -> Address {
e.storage()
.instance()
.extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT);
read_escrow_id(&e)
read_escrow_contract(&e)
}

/// Transfer the mint authority to a new admin address.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,22 @@ pub fn write_metadata(e: &Env, metadata: TokenMetadata) {
util.metadata().set_metadata(&metadata);
}

// Immutable metadata (escrow_id, mint_authority) - set only once at initialization
pub fn read_escrow_id(e: &Env) -> String {
let key = DataKey::EscrowId;
// Immutable metadata (escrow_contract, mint_authority) - set only once at initialization
pub fn read_escrow_contract(e: &Env) -> Address {
let key = DataKey::EscrowContract;
e.storage()
.instance()
.get(&key)
.expect("Escrow ID not initialized")
.expect("Escrow contract not initialized")
}

pub fn write_escrow_id(e: &Env, escrow_id: &String) {
let key = DataKey::EscrowId;
pub fn write_escrow_contract(e: &Env, escrow_contract: &Address) {
let key = DataKey::EscrowContract;
// Check if already set (immutable - can only be set once)
if e.storage().instance().has(&key) {
panic!("Escrow ID already set - cannot modify");
panic!("Escrow contract already set - cannot modify");
}
e.storage().instance().set(&key, escrow_id);
e.storage().instance().set(&key, escrow_contract);
}

pub fn read_mint_authority(e: &Env) -> Address {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ pub enum DataKey {
Balance(Address),
State(Address),
// Immutable metadata keys (set only once at initialization)
EscrowId,
EscrowContract,
MintAuthority,
}
Loading