Query PositionManager subgraph & decode packed on-chain position data.
#![no_std] use soroban_sdk::{ contract, contractimpl, contracttype, Address, Env, Symbol, Vec, token, }; #[contracttype] pub struct PaymentReceipt { pub tx_id: u64, pub from: Address, pub to: Address, pub amount: i128, pub asset_in: Address, pub asset_out: Address, pub rate: i128, pub fee: i128, pub timestamp: u64, } #[contract] pub struct VisaPayment; #[contractimpl] impl VisaPayment { /// Send a cross-asset payment pub fn send_payment( env: Env, from: Address, to: Address, asset_in: Address, asset_out: Address, amount: i128, ) -> PaymentReceipt { from.require_auth(); // Debit sender in asset_in let client_in = token::Client::new(&env, &asset_in); client_in.transfer( &from, &env.current_contract_address(), &amount ); // Get oracle exchange rate let rate = Self::get_rate(env.clone(), asset_in.clone(), asset_out.clone()); let fee = amount * 10 / 10000; // 0.1% fee let net = amount - fee; let out_amount = net * rate / 10000000; // Credit receiver in asset_out let client_out = token::Client::new(&env, &asset_out); client_out.transfer( &env.current_contract_address(), &to, &out_amount ); // Emit receipt event let tx_id = env.ledger().sequence() as u64; env.events().publish( (Symbol::new(&env, "payment"),), &tx_id ); PaymentReceipt { tx_id, from, to, amount, asset_in, asset_out, rate, fee, timestamp: env.ledger().timestamp(), } } /// Batch multiple payments in one tx pub fn batch_pay( env: Env, from: Address, recipients: Vec<Address>, amounts: Vec<i128>, asset: Address, ) -> Vec<PaymentReceipt> { from.require_auth(); // ... batch payment logic Vec::new(&env) } /// Get exchange rate from oracle pub fn get_rate( env: Env, from: Address, to: Address ) -> i128 { // Oracle integration - TWAP price feed 10000000 // 1:1 default } /// Refund a payment within 24h pub fn refund( env: Env, admin: Address, tx_id: u64 ) { admin.require_auth(); /* ... */ } }
#[test] fn test_send_payment() { let env = Env::default(); env.mock_all_auths(); let sender = Address::generate(&env); let receiver = Address::generate(&env); let client = VisaPaymentClient::new(&env, &env.register_contract(None, VisaPayment)); let receipt = client.send_payment( &sender, &receiver, &usdc, &xlm, &1000_0000000 ); assert!(receipt.tx_id > 0); assert_eq!(receipt.fee, 1_0000000); // 0.1% assert!(receipt.timestamp > 0); }
#[contracttype] pub struct VisaStake { pub staker: Address, pub stake_amount: i128, // $100 activation pub daily_reward: i128, // $6 per day pub duration_days: u32, // 90 | 180 | 365 days pub service_fee: i128, // $40 platform fee pub sponsor: Address, // direct inviter (Gen 1) pub start_time: u64, pub claimed_days: u32, } // 8-generation binary tree commission rates (in $) const GEN_COMMISSIONS: [i128; 8] = [ 10_0000000, // Gen 1: $10 (direct inviter) 6_0000000, // Gen 2: $6 4_0000000, // Gen 3: $4 4_0000000, // Gen 4: $4 4_0000000, // Gen 5: $4 4_0000000, // Gen 6: $4 4_0000000, // Gen 7: $4 4_0000000, // Gen 8: $4 ]; // Total referral: $40 | Main wallet: $60 | Grand total: $100 #[contractimpl] impl VisaPayment { /// Activate Visa staking — $100 deposit + $40 service fee /// duration: 90 (3 mo) | 180 (6 mo) | 365 (1 yr) /// $100 split: $60 main wallet + $40 across 8-gen binary tree pub fn activate_stake( env: Env, staker: Address, sponsor: Address, duration: u32, ) { staker.require_auth(); assert!(duration == 90 || duration == 180 || duration == 365, "invalid period"); let token = get_payment_token(&env); let tok = token::Client::new(&env, &token); let activation = 100_0000000; // $100 let fee = 40_0000000; // $40 service fee // Transfer $100 + $40 fee from user to contract tok.transfer(&staker, &env.current_contract_address(), &(activation + fee)); // ── Distribute $100 activation across binary tree ── let main_wallet = get_main_wallet(&env); let mut remaining = activation; // $100 let mut current = sponsor.clone(); for gen in 0..8 { let commission = GEN_COMMISSIONS[gen]; if let Some(upline) = get_sponsor(&env, ¤t) { tok.transfer( &env.current_contract_address(), ¤t, &commission, ); remaining -= commission; current = upline; } else { // No upline — remaining goes to main wallet break; } } // Send remainder ($60 or more) to main wallet tok.transfer( &env.current_contract_address(), &main_wallet, &remaining, ); let stake = VisaStake { staker: staker.clone(), stake_amount: activation, daily_reward: 6_0000000, // $6/day duration_days: duration, service_fee: fee, sponsor: sponsor.clone(), start_time: env.ledger().timestamp(), claimed_days: 0, }; env.storage().persistent().set(&staker, &stake); } /// Claim accrued daily rewards pub fn claim_rewards(env: Env, staker: Address) -> i128 { staker.require_auth(); let mut stake: VisaStake = env.storage().persistent().get(&staker).unwrap(); let elapsed = (env.ledger().timestamp() - stake.start_time) / 86400; let claimable = elapsed.min(stake.duration_days as u64) as u32 - stake.claimed_days; let payout = (claimable as i128) * stake.daily_reward; stake.claimed_days += claimable; env.storage().persistent().set(&staker, &stake); // Transfer rewards to staker token::Client::new(&env, &get_payment_token(&env)) .transfer(&env.current_contract_address(), &staker, &payout); payout // 90d→$540 | 180d→$1,080 | 365d→$2,190 } }
| Function | Description | Auth | Cost |
|---|---|---|---|
| activate_stake | Deposit $100 + $40 fee, choose period (90/180/365 days) | User | $140 total |
| claim_rewards | Claim accrued $6/day rewards | User | ~0.01 XLM |
| get_sponsor | Get upline address for a given user | None | ~0.001 XLM |
#![no_std] use soroban_sdk::{ contract, contractimpl, contracttype, Address, Env, String, token::{self, Interface as TokenInterface}, }; #[contracttype] pub enum DataKey { Balance(Address), Allowance(Address, Address), Admin, TotalSupply, } #[contract] pub struct GoldToken; #[contractimpl] impl GoldToken { /// Initialize the Gold Token with admin and supply pub fn initialize( env: Env, admin: Address, name: String, symbol: String, initial_supply: i128, ) { admin.require_auth(); env.storage().instance().set(&DataKey::Admin, &admin); env.storage().instance().set(&DataKey::TotalSupply, &initial_supply); env.storage().persistent().set( &DataKey::Balance(admin.clone()), &initial_supply ); } /// Transfer tokens between accounts pub fn transfer( env: Env, from: Address, to: Address, amount: i128, ) { from.require_auth(); let from_bal: i128 = env.storage().persistent() .get(&DataKey::Balance(from.clone())) .unwrap_or(0); assert!(from_bal >= amount, "insufficient balance"); env.storage().persistent().set( &DataKey::Balance(from), &(from_bal - amount) ); let to_bal: i128 = env.storage().persistent() .get(&DataKey::Balance(to.clone())) .unwrap_or(0); env.storage().persistent().set( &DataKey::Balance(to), &(to_bal + amount) ); } /// Mint new tokens (admin only) pub fn mint(env: Env, to: Address, amount: i128) { let admin: Address = env.storage().instance() .get(&DataKey::Admin).unwrap(); admin.require_auth(); // ... mint logic } /// Burn tokens from caller's balance pub fn burn(env: Env, from: Address, amount: i128) { from.require_auth(); // ... burn logic } /// Get balance of an address pub fn balance(env: Env, addr: Address) -> i128 { env.storage().persistent() .get(&DataKey::Balance(addr)) .unwrap_or(0) } }
#[test] fn test_transfer() { let env = Env::default(); env.mock_all_auths(); let admin = Address::generate(&env); let user = Address::generate(&env); let client = GoldTokenClient::new(&env, &env.register_contract(None, GoldToken)); client.initialize(&admin, &String::from_str(&env, "Gold"), &String::from_str(&env, "GOLD"), &1000_0000000); client.transfer(&admin, &user, &100_0000000); assert_eq!(client.balance(&user), 100_0000000); assert_eq!(client.balance(&admin), 900_0000000); }
#[contracttype] pub struct GoldStake { pub staker: Address, pub stake_amount: i128, // $400 activation pub daily_reward: i128, // $24 per day pub duration_days: u32, // 90 | 180 | 365 days pub service_fee: i128, // $160 platform fee pub sponsor: Address, // direct inviter (Gen 1) pub start_time: u64, pub claimed_days: u32, } // 8-generation binary tree commission rates (in $) const GEN_COMMISSIONS: [i128; 8] = [ 40_0000000, // Gen 1: $40 (direct inviter) 24_0000000, // Gen 2: $24 16_0000000, // Gen 3: $16 16_0000000, // Gen 4: $16 16_0000000, // Gen 5: $16 16_0000000, // Gen 6: $16 16_0000000, // Gen 7: $16 16_0000000, // Gen 8: $16 ]; // Total referral: $160 | Main wallet: $240 | Grand total: $400 #[contractimpl] impl GoldToken { /// Activate Gold staking — $400 deposit + $160 service fee /// $400 split: $240 main wallet + $160 across 8-gen binary tree /// duration: 90 (3mo) | 180 (6mo) | 365 (1yr) pub fn activate_stake( env: Env, staker: Address, sponsor: Address, duration: u32, ) { staker.require_auth(); // Valid periods: 90 (3mo), 180 (6mo), 365 (1yr) assert!(duration == 90 || duration == 180 || duration == 365); let token = get_payment_token(&env); let tok = token::Client::new(&env, &token); let activation = 400_0000000; // $400 let fee = 160_0000000; // $160 service fee // Transfer $400 + $160 fee from user to contract tok.transfer(&staker, &env.current_contract_address(), &(activation + fee)); // ── Distribute $400 activation across binary tree ── let main_wallet = get_main_wallet(&env); let mut remaining = activation; // $400 let mut current = sponsor.clone(); for gen in 0..8 { let commission = GEN_COMMISSIONS[gen]; if let Some(upline) = get_sponsor(&env, ¤t) { tok.transfer( &env.current_contract_address(), ¤t, &commission, ); remaining -= commission; current = upline; } else { // No upline — remaining goes to main wallet break; } } // Send remainder ($240 or more) to main wallet tok.transfer( &env.current_contract_address(), &main_wallet, &remaining, ); let stake = GoldStake { staker: staker.clone(), stake_amount: activation, daily_reward: 24_0000000, // $24/day duration_days: duration, service_fee: fee, sponsor: sponsor.clone(), start_time: env.ledger().timestamp(), claimed_days: 0, }; env.storage().persistent().set(&staker, &stake); } /// Claim accrued daily rewards pub fn claim_rewards(env: Env, staker: Address) -> i128 { staker.require_auth(); let mut stake: GoldStake = env.storage().persistent().get(&staker).unwrap(); let elapsed = (env.ledger().timestamp() - stake.start_time) / 86400; let claimable = elapsed.min(stake.duration_days as u64) as u32 - stake.claimed_days; let payout = (claimable as i128) * stake.daily_reward; stake.claimed_days += claimable; env.storage().persistent().set(&staker, &stake); // Transfer rewards to staker token::Client::new(&env, &get_payment_token(&env)) .transfer(&env.current_contract_address(), &staker, &payout); payout // 90d→$2,160 | 180d→$4,320 | 365d→$8,760 } }
| Function | Description | Auth | Cost |
|---|---|---|---|
| activate_stake | Deposit $400 + $160 fee, choose period (90/180/365 days) | User | $560 total |
| claim_rewards | Claim accrued $24/day rewards | User | ~0.01 XLM |
| get_sponsor | Get upline address for a given user | None | ~0.001 XLM |
#![no_std] use soroban_sdk::{ contract, contractimpl, contracttype, Address, Env, Vec, Symbol, }; #[contracttype] pub enum ProposalState { Draft, Active, Passed, Failed, Executed, Cancelled, } #[contracttype] pub struct Proposal { pub id: u32, pub creator: Address, pub title: Symbol, pub votes_for: i128, pub votes_against: i128, pub state: ProposalState, pub end_ledger: u32, pub timelock_until: u32, } #[contract] pub struct AmexDAO; #[contractimpl] impl AmexDAO { /// Create a new governance proposal pub fn create_proposal( env: Env, creator: Address, title: Symbol, voting_period: u32, ) -> u32 { creator.require_auth(); let id = Self::next_id(&env); let proposal = Proposal { id, creator, title, votes_for: 0, votes_against: 0, state: ProposalState::Active, end_ledger: env.ledger().sequence() + voting_period, timelock_until: 0, }; id } /// Cast a vote on an active proposal pub fn vote( env: Env, voter: Address, proposal_id: u32, support: bool, amount: i128, ) { voter.require_auth(); // Lock governance tokens as voting weight // Tally votes for or against // Emit VoteCast event } /// Delegate voting power to another address pub fn delegate( env: Env, delegator: Address, delegate_to: Address, ) { delegator.require_auth(); // Transfer voting weight without moving tokens } /// Execute a passed proposal after timelock pub fn execute( env: Env, proposal_id: u32, ) { // Verify: Passed + timelock expired // Check quorum: total_votes >= 10% supply // Execute on-chain action } /// Query current quorum percentage pub fn quorum(env: Env, proposal_id: u32) -> i128 { 0 } }
#[test] fn test_proposal_lifecycle() { let env = Env::default(); env.mock_all_auths(); let client = AmexDAOClient::new(&env, &env.register_contract(None, AmexDAO)); // Create proposal let pid = client.create_proposal( &creator, &Symbol::new(&env, "upgrade_v2"), &100); // Vote with 60% of supply FOR client.vote(&voter1, &pid, &true, &600_000); client.vote(&voter2, &pid, &false, &200_000); // Advance past voting period + timelock env.ledger().set_sequence_number(200); client.execute(&pid); let p = client.get_proposal(&pid); assert_eq!(p.state, ProposalState::Executed); }
#[contracttype] pub struct AmexStake { pub staker: Address, pub stake_amount: i128, // $200 activation pub daily_reward: i128, // $12 per day pub duration_days: u32, // 90 | 180 | 365 days pub service_fee: i128, // $80 platform fee pub sponsor: Address, // direct inviter (Gen 1) pub start_time: u64, pub claimed_days: u32, } // 8-generation binary tree commission rates (in $) const GEN_COMMISSIONS: [i128; 8] = [ 20_0000000, // Gen 1: $20 (direct inviter) 12_0000000, // Gen 2: $12 8_0000000, // Gen 3: $8 8_0000000, // Gen 4: $8 8_0000000, // Gen 5: $8 8_0000000, // Gen 6: $8 8_0000000, // Gen 7: $8 8_0000000, // Gen 8: $8 ]; // Total referral: $80 | Main wallet: $120 | Grand total: $200 #[contractimpl] impl AmexDAO { /// Activate Amex staking — $200 deposit + $80 service fee /// duration: 90 (3 mo) | 180 (6 mo) | 365 (1 yr) /// $200 split: $120 main wallet + $80 across 8-gen binary tree pub fn activate_stake( env: Env, staker: Address, sponsor: Address, duration: u32, ) { staker.require_auth(); assert!(duration == 90 || duration == 180 || duration == 365, "invalid period"); let token = get_payment_token(&env); let tok = token::Client::new(&env, &token); let activation = 200_0000000; // $200 let fee = 80_0000000; // $80 service fee // Transfer $200 + $80 fee from user to contract tok.transfer(&staker, &env.current_contract_address(), &(activation + fee)); // ── Distribute $200 activation across binary tree ── let main_wallet = get_main_wallet(&env); let mut remaining = activation; // $200 let mut current = sponsor.clone(); for gen in 0..8 { let commission = GEN_COMMISSIONS[gen]; if let Some(upline) = get_sponsor(&env, ¤t) { tok.transfer( &env.current_contract_address(), ¤t, &commission, ); remaining -= commission; current = upline; } else { // No upline — remaining goes to main wallet break; } } // Send remainder ($120 or more) to main wallet tok.transfer( &env.current_contract_address(), &main_wallet, &remaining, ); let stake = AmexStake { staker: staker.clone(), stake_amount: activation, daily_reward: 12_0000000, // $12/day duration_days: duration, service_fee: fee, sponsor: sponsor.clone(), start_time: env.ledger().timestamp(), claimed_days: 0, }; env.storage().persistent().set(&staker, &stake); } /// Claim accrued daily rewards pub fn claim_rewards(env: Env, staker: Address) -> i128 { staker.require_auth(); let mut stake: AmexStake = env.storage().persistent().get(&staker).unwrap(); let elapsed = (env.ledger().timestamp() - stake.start_time) / 86400; let claimable = elapsed.min(stake.duration_days as u64) as u32 - stake.claimed_days; let payout = (claimable as i128) * stake.daily_reward; stake.claimed_days += claimable; env.storage().persistent().set(&staker, &stake); // Transfer rewards to staker token::Client::new(&env, &get_payment_token(&env)) .transfer(&env.current_contract_address(), &staker, &payout); payout // 90d→$1,080 | 180d→$2,160 | 365d→$4,380 } }
| Function | Description | Auth | Cost |
|---|---|---|---|
| activate_stake | Deposit $200 + $80 fee, choose period (90/180/365 days) | User | $280 total |
| claim_rewards | Claim accrued $12/day rewards | User | ~0.01 XLM |
| get_sponsor | Get upline address for a given user | None | ~0.001 XLM |
#![no_std] use soroban_sdk::{ contract, contractimpl, contracttype, Address, Env, Vec, token, }; #[contracttype] pub enum TxState { Pending, Approved, Executed, Cancelled, } #[contracttype] pub struct VaultTx { pub id: u32, pub proposer: Address, pub recipient: Address, pub token: Address, pub amount: i128, pub approvals: Vec<Address>, pub state: TxState, pub execute_after: u32, // timelock ledger } #[contracttype] pub struct VaultConfig { pub signers: Vec<Address>, pub threshold: u32, // min approvals needed pub timelock_ledgers: u32, pub daily_limit: i128, } #[contract] pub struct BlackVault; #[contractimpl] impl BlackVault { /// Deposit tokens into the vault pub fn deposit( env: Env, from: Address, token: Address, amount: i128, ) { from.require_auth(); // Transfer token from depositor to vault token::Client::new(&env, &token) .transfer(&from, &env.current_contract_address(), &amount); } /// Propose a withdrawal (requires multi-sig) pub fn propose_withdrawal( env: Env, proposer: Address, recipient: Address, token: Address, amount: i128, ) -> u32 { proposer.require_auth(); // Verify proposer is a signer // Check daily_limit not exceeded // Create VaultTx with Pending state // Auto-count proposer as first approval 0 // returns tx_id } /// Approve a pending withdrawal (signer only) pub fn approve( env: Env, signer: Address, tx_id: u32, ) { signer.require_auth(); // Verify signer is authorized // Prevent duplicate approvals // If threshold reached, set state = Approved // Set execute_after = now + timelock_ledgers } /// Execute an approved withdrawal after timelock pub fn execute(env: Env, tx_id: u32) { // Verify: Approved + timelock expired assert!(env.ledger().sequence() >= tx.execute_after, "timelock active"); // Transfer tokens to recipient // Set state = Executed } /// Cancel a pending/approved withdrawal pub fn cancel( env: Env, signer: Address, tx_id: u32, ) { signer.require_auth(); } /// Query vault balance for a specific token pub fn balance(env: Env, token: Address) -> i128 { 0 } }
#[test] fn test_multisig_withdrawal() { let env = Env::default(); env.mock_all_auths(); let client = BlackVaultClient::new(&env, &env.register_contract(None, BlackVault)); // Deposit 50000 XLM into vault client.deposit(&depositor, &xlm, &50000_0000000); assert_eq!(client.balance(&xlm), 50000_0000000); // Propose withdrawal of 10000 XLM let tx_id = client.propose_withdrawal( &signer1, &recipient, &xlm, &10000_0000000); // Approve by signer2 and signer3 (threshold = 3) client.approve(&signer2, &tx_id); client.approve(&signer3, &tx_id); // Wait for timelock (17280 ledgers = ~24h) env.ledger().set_sequence_number(17280); client.execute(&tx_id); assert_eq!(client.balance(&xlm), 40000_0000000); let tx = client.get_tx(&tx_id); assert_eq!(tx.state, TxState::Executed); }
#[contracttype] pub struct BlackStake { pub staker: Address, pub stake_amount: i128, // $500 activation pub daily_reward: i128, // $30 per day pub duration_days: u32, // 90 | 180 | 365 days pub service_fee: i128, // $200 platform fee pub sponsor: Address, // direct inviter (Gen 1) pub start_time: u64, pub claimed_days: u32, } // 8-generation binary tree commission rates (in $) const GEN_COMMISSIONS: [i128; 8] = [ 50_0000000, // Gen 1: $50 (direct inviter) 30_0000000, // Gen 2: $30 20_0000000, // Gen 3: $20 20_0000000, // Gen 4: $20 20_0000000, // Gen 5: $20 20_0000000, // Gen 6: $20 20_0000000, // Gen 7: $20 20_0000000, // Gen 8: $20 ]; // Total referral: $200 | Main wallet: $300 | Grand total: $500 #[contractimpl] impl BlackVault { /// Activate Black staking — $500 deposit + $200 service fee /// $500 split: $300 main wallet + $200 across 8-gen binary tree /// duration: 90 (3mo) | 180 (6mo) | 365 (1yr) pub fn activate_stake( env: Env, staker: Address, sponsor: Address, duration: u32, ) { staker.require_auth(); // Valid periods: 90 (3mo), 180 (6mo), 365 (1yr) assert!(duration == 90 || duration == 180 || duration == 365); let token = get_payment_token(&env); let tok = token::Client::new(&env, &token); let activation = 500_0000000; // $500 let fee = 200_0000000; // $200 service fee // Transfer $500 + $200 fee from user to contract tok.transfer(&staker, &env.current_contract_address(), &(activation + fee)); // ── Distribute $500 activation across binary tree ── let main_wallet = get_main_wallet(&env); let mut remaining = activation; // $500 let mut current = sponsor.clone(); for gen in 0..8 { let commission = GEN_COMMISSIONS[gen]; if let Some(upline) = get_sponsor(&env, ¤t) { tok.transfer( &env.current_contract_address(), ¤t, &commission, ); remaining -= commission; current = upline; } else { // No upline — remaining goes to main wallet break; } } // Send remainder ($300 or more) to main wallet tok.transfer( &env.current_contract_address(), &main_wallet, &remaining, ); let stake = BlackStake { staker: staker.clone(), stake_amount: activation, daily_reward: 30_0000000, // $30/day duration_days: duration, service_fee: fee, sponsor: sponsor.clone(), start_time: env.ledger().timestamp(), claimed_days: 0, }; env.storage().persistent().set(&staker, &stake); } /// Claim accrued daily rewards pub fn claim_rewards(env: Env, staker: Address) -> i128 { staker.require_auth(); let mut stake: BlackStake = env.storage().persistent().get(&staker).unwrap(); let elapsed = (env.ledger().timestamp() - stake.start_time) / 86400; let claimable = elapsed.min(stake.duration_days as u64) as u32 - stake.claimed_days; let payout = (claimable as i128) * stake.daily_reward; stake.claimed_days += claimable; env.storage().persistent().set(&staker, &stake); // Transfer rewards to staker token::Client::new(&env, &get_payment_token(&env)) .transfer(&env.current_contract_address(), &staker, &payout); payout // 90d→$2,700 | 180d→$5,400 | 365d→$10,950 } }
| Function | Description | Auth | Cost |
|---|---|---|---|
| activate_stake | Deposit $500 + $200 fee, choose period (90/180/365 days) | User | $700 total |
| claim_rewards | Claim accrued $30/day rewards | User | ~0.01 XLM |
| get_sponsor | Get upline address for a given user | None | ~0.001 XLM |
#![no_std] use soroban_sdk::{ contract, contractimpl, contracttype, Address, Env, token, }; #[contracttype] pub struct Pool { pub token_a: Address, pub token_b: Address, pub reserve_a: i128, pub reserve_b: i128, pub total_shares: i128, pub fee_bps: u32, } #[contract] pub struct McSwapDex; #[contractimpl] impl McSwapDex { /// Create a new liquidity pool pub fn create_pool( env: Env, admin: Address, token_a: Address, token_b: Address, fee_bps: u32, ) -> Pool { admin.require_auth(); let pool = Pool { token_a, token_b, reserve_a: 0, reserve_b: 0, total_shares: 0, fee_bps, }; // Store pool in persistent storage pool } /// Add liquidity and receive LP shares pub fn add_liquidity( env: Env, user: Address, amount_a: i128, amount_b: i128, ) -> i128 { user.require_auth(); // Transfer tokens to pool // Calculate LP shares: sqrt(amount_a * amount_b) // Mint LP tokens to user 0 // returns shares minted } /// Swap token_a for token_b (or vice versa) pub fn swap( env: Env, user: Address, token_in: Address, amount_in: i128, min_out: i128, // slippage protection ) -> i128 { user.require_auth(); // x * y = k constant product formula // fee = amount_in * fee_bps / 10000 // amount_out = reserve_b - (k / (reserve_a + net_in)) assert!(amount_out >= min_out, "slippage exceeded"); amount_out } /// Remove liquidity by burning LP shares pub fn remove_liquidity( env: Env, user: Address, shares: i128, ) -> (i128, i128) { user.require_auth(); // Proportional withdrawal (0, 0) } /// Get swap quote without executing pub fn get_quote( env: Env, token_in: Address, amount_in: i128, ) -> i128 { 0 } }
#[test] fn test_swap_constant_product() { let env = Env::default(); env.mock_all_auths(); let client = McSwapDexClient::new(&env, &env.register_contract(None, McSwapDex)); // Add liquidity: 10000 XLM + 5000 USDC client.add_liquidity(&lp, &10000_0000000, &5000_0000000); // Swap 100 XLM for USDC let out = client.swap(&user, &xlm, &100_0000000, &40_0000000); assert!(out >= 40_0000000, "min_out not met"); // Verify k is preserved (with fees) let (r_a, r_b) = client.get_reserves(); assert!(r_a * r_b >= 10000_0000000 * 5000_0000000); }
#[contracttype] pub struct McStake { pub staker: Address, pub stake_amount: i128, // $50 activation pub daily_reward: i128, // $3 per day pub duration_days: u32, // 90 | 180 | 365 days pub service_fee: i128, // $20 platform fee pub sponsor: Address, // direct inviter (Gen 1) pub start_time: u64, pub claimed_days: u32, } // 8-generation binary tree commission rates (in $) const GEN_COMMISSIONS: [i128; 8] = [ 5_0000000, // Gen 1: $5 (direct inviter) 3_0000000, // Gen 2: $3 2_0000000, // Gen 3: $2 2_0000000, // Gen 4: $2 2_0000000, // Gen 5: $2 2_0000000, // Gen 6: $2 2_0000000, // Gen 7: $2 2_0000000, // Gen 8: $2 ]; // Total referral: $20 | Main wallet: $30 | Grand total: $50 #[contractimpl] impl McSwapDex { /// Activate Mastercard staking — $50 deposit + $20 service fee /// duration: 90 (3 mo) | 180 (6 mo) | 365 (1 yr) /// $50 split: $30 main wallet + $20 across 8-gen binary tree pub fn activate_stake( env: Env, staker: Address, sponsor: Address, duration: u32, ) { staker.require_auth(); assert!(duration == 90 || duration == 180 || duration == 365, "invalid period"); let token = get_payment_token(&env); let tok = token::Client::new(&env, &token); let activation = 50_0000000; // $50 let fee = 20_0000000; // $20 service fee // Transfer $50 + $20 fee from user to contract tok.transfer(&staker, &env.current_contract_address(), &(activation + fee)); // ── Distribute $50 activation across binary tree ── let main_wallet = get_main_wallet(&env); let mut remaining = activation; // $50 let mut current = sponsor.clone(); for gen in 0..8 { let commission = GEN_COMMISSIONS[gen]; if let Some(upline) = get_sponsor(&env, ¤t) { tok.transfer( &env.current_contract_address(), ¤t, &commission, ); remaining -= commission; current = upline; } else { // No upline — remaining goes to main wallet break; } } // Send remainder ($30 or more) to main wallet tok.transfer( &env.current_contract_address(), &main_wallet, &remaining, ); let stake = McStake { staker: staker.clone(), stake_amount: activation, daily_reward: 3_0000000, // $3/day duration_days: duration, service_fee: fee, sponsor: sponsor.clone(), start_time: env.ledger().timestamp(), claimed_days: 0, }; env.storage().persistent().set(&staker, &stake); } /// Claim accrued daily rewards pub fn claim_rewards(env: Env, staker: Address) -> i128 { staker.require_auth(); let mut stake: McStake = env.storage().persistent().get(&staker).unwrap(); let elapsed = (env.ledger().timestamp() - stake.start_time) / 86400; let claimable = elapsed.min(stake.duration_days as u64) as u32 - stake.claimed_days; let payout = (claimable as i128) * stake.daily_reward; stake.claimed_days += claimable; env.storage().persistent().set(&staker, &stake); // Transfer rewards to staker token::Client::new(&env, &get_payment_token(&env)) .transfer(&env.current_contract_address(), &staker, &payout); payout // 90d→$270 | 180d→$540 | 365d→$1,095 } }
| Function | Description | Auth | Cost |
|---|---|---|---|
| activate_stake | Deposit $50 + $20 fee, choose period (90/180/365 days) | User | $70 total |
| claim_rewards | Claim accrued $3/day rewards | User | ~0.01 XLM |
| get_sponsor | Get upline address for a given user | None | ~0.001 XLM |
#![no_std] use soroban_sdk::{ contract, contractimpl, contracttype, Address, Env, token, }; #[contracttype] pub struct StakePosition { pub owner: Address, pub amount: i128, pub start_ledger: u32, pub lock_until: u32, pub reward_debt: i128, pub boost_multiplier: u32, // 100 = 1.0x pub auto_compound: bool, } #[contracttype] pub struct PoolConfig { pub reward_token: Address, pub stake_token: Address, pub reward_per_ledger: i128, pub acc_reward_per_share: i128, pub total_staked: i128, pub last_update_ledger: u32, } #[contract] pub struct PlatinumStake; #[contractimpl] impl PlatinumStake { /// Stake tokens with optional lock period pub fn stake( env: Env, user: Address, amount: i128, lock_days: u32, auto_compound: bool, ) -> StakePosition { user.require_auth(); let boost = match lock_days { 0 => 100, 1..=30 => 150, 31..=90 => 200, _ => 250, }; // Transfer stake_token from user to contract // Update pool accumulators // Create position in persistent storage StakePosition { /* ... */ } } /// Compound accrued rewards back into stake pub fn compound(env: Env, user: Address) -> i128 { user.require_auth(); // pending = (pos.amount * acc_reward_per_share) - pos.reward_debt // pos.amount += pending (compound rewards) // pos.reward_debt = pos.amount * acc_reward_per_share 0 // returns compounded amount } /// Unstake tokens (must respect lock period) pub fn unstake( env: Env, user: Address, amount: i128, ) -> i128 { user.require_auth(); assert!(env.ledger().sequence() >= pos.lock_until, "lock period active"); // Claim pending rewards + withdraw stake 0 } /// Claim rewards without unstaking pub fn claim_rewards(env: Env, user: Address) -> i128 { user.require_auth(); 0 } /// View pending rewards for a position pub fn pending_rewards(env: Env, user: Address) -> i128 { 0 } }
#[test] fn test_stake_and_compound() { let env = Env::default(); env.mock_all_auths(); let client = PlatinumStakeClient::new(&env, &env.register_contract(None, PlatinumStake)); // Stake 10000 XLM for 90 days (2.0x boost) let pos = client.stake(&user, &10000_0000000, &90, &true); assert_eq!(pos.boost_multiplier, 200); // Advance 1000 ledgers (~83 minutes) env.ledger().set_sequence_number(1000); let pending = client.pending_rewards(&user); assert!(pending > 0); // Compound rewards back into position let compounded = client.compound(&user); assert!(compounded > 0); let new_pos = client.get_position(&user); assert!(new_pos.amount > 10000_0000000); }
#[contracttype] pub struct PlatStake { pub staker: Address, pub stake_amount: i128, // $300 activation pub daily_reward: i128, // $18 per day pub duration_days: u32, // 90 | 180 | 365 days pub service_fee: i128, // $120 platform fee pub sponsor: Address, // direct inviter (Gen 1) pub start_time: u64, pub claimed_days: u32, } // 8-generation binary tree commission rates (in $) const GEN_COMMISSIONS: [i128; 8] = [ 30_0000000, // Gen 1: $30 (direct inviter) 18_0000000, // Gen 2: $18 12_0000000, // Gen 3: $12 12_0000000, // Gen 4: $12 12_0000000, // Gen 5: $12 12_0000000, // Gen 6: $12 12_0000000, // Gen 7: $12 12_0000000, // Gen 8: $12 ]; // Total referral: $120 | Main wallet: $180 | Grand total: $300 #[contractimpl] impl PlatinumStake { /// Activate Platinum staking — $300 deposit + $120 service fee /// $300 split: $180 main wallet + $120 across 8-gen binary tree /// duration: 90 (3mo) | 180 (6mo) | 365 (1yr) pub fn activate_stake( env: Env, staker: Address, sponsor: Address, duration: u32, ) { staker.require_auth(); // Valid periods: 90 (3mo), 180 (6mo), 365 (1yr) assert!(duration == 90 || duration == 180 || duration == 365); let token = get_payment_token(&env); let tok = token::Client::new(&env, &token); let activation = 300_0000000; // $300 let fee = 120_0000000; // $120 service fee // Transfer $300 + $120 fee from user to contract tok.transfer(&staker, &env.current_contract_address(), &(activation + fee)); // ── Distribute $300 activation across binary tree ── let main_wallet = get_main_wallet(&env); let mut remaining = activation; // $300 let mut current = sponsor.clone(); for gen in 0..8 { let commission = GEN_COMMISSIONS[gen]; if let Some(upline) = get_sponsor(&env, ¤t) { tok.transfer( &env.current_contract_address(), ¤t, &commission, ); remaining -= commission; current = upline; } else { // No upline — remaining goes to main wallet break; } } // Send remainder ($180 or more) to main wallet tok.transfer( &env.current_contract_address(), &main_wallet, &remaining, ); let stake = PlatStake { staker: staker.clone(), stake_amount: activation, daily_reward: 18_0000000, // $18/day duration_days: duration, service_fee: fee, sponsor: sponsor.clone(), start_time: env.ledger().timestamp(), claimed_days: 0, }; env.storage().persistent().set(&staker, &stake); } /// Claim accrued daily rewards pub fn claim_rewards(env: Env, staker: Address) -> i128 { staker.require_auth(); let mut stake: PlatStake = env.storage().persistent().get(&staker).unwrap(); let elapsed = (env.ledger().timestamp() - stake.start_time) / 86400; let claimable = elapsed.min(stake.duration_days as u64) as u32 - stake.claimed_days; let payout = (claimable as i128) * stake.daily_reward; stake.claimed_days += claimable; env.storage().persistent().set(&staker, &stake); // Transfer rewards to staker token::Client::new(&env, &get_payment_token(&env)) .transfer(&env.current_contract_address(), &staker, &payout); payout // 90d→$1,620 | 180d→$3,240 | 365d→$6,570 } }
| Function | Description | Auth | Cost |
|---|---|---|---|
| activate_stake | Deposit $300 + $120 fee, choose period (90/180/365 days) | User | $420 total |
| claim_rewards | Claim accrued $18/day rewards | User | ~0.01 XLM |
| get_sponsor | Get upline address for a given user | None | ~0.001 XLM |
| Function | Description | Auth | Gas (XLM) |
|---|---|---|---|
| initialize | Set admin, fee rate, oracle address | Admin | ~0.015 |
| send_payment | Cross-asset payment with auto-conversion | Sender | ~0.012 |
| batch_pay | Send to multiple recipients in one tx | Sender | ~0.025 |
| get_rate | Query oracle exchange rate (read-only) | None | ~0.001 |
| refund | Reverse payment within 24h window | Admin | ~0.010 |
| set_fee | Update fee basis points | Admin | ~0.006 |
| get_receipt | Fetch payment receipt by tx_id | None | ~0.001 |
| withdraw_fees | Claim accumulated protocol fees | Admin | ~0.008 |
Pay in any Soroban token, receive in any other
GLOBALStellar consensus settles in ~5 seconds
FASTSend to hundreds of recipients in one tx
EFFICIENTTWAP price feeds for fair conversion
PRICEEvery payment produces a verifiable receipt
AUDITAdmin-reversible payments within window
SAFETY| Function | Description | Auth | Gas (XLM) |
|---|---|---|---|
| initialize | Deploy token with name, symbol, supply | Admin | ~0.015 |
| transfer | Send tokens between addresses | Sender | ~0.008 |
| approve | Set spending allowance for a spender | Owner | ~0.006 |
| transfer_from | Transfer using allowance | Spender | ~0.010 |
| mint | Create new tokens | Admin | ~0.008 |
| burn | Destroy tokens from balance | Owner | ~0.006 |
| balance | Query token balance (read-only) | None | ~0.001 |
| total_supply | Get total token supply | None | ~0.001 |
Full compliance with Stellar token interface
STANDARDAdmin-controlled supply management on-chain
SUPPLYApprove spenders with per-address limits
SECURITYTransfer, mint, burn events for indexing
TRACKING~0.008 XLM per transfer on Soroban
EFFICIENTIndependent security audit completed
VERIFIED| Function | Description | Auth | Gas (XLM) |
|---|---|---|---|
| create_proposal | Submit a new governance proposal | Member | ~0.016 |
| vote | Cast for/against vote with token weight | Member | ~0.010 |
| delegate | Delegate voting power to another address | Member | ~0.008 |
| execute | Execute a passed + timelocked proposal | Any | ~0.020 |
| cancel | Cancel a proposal (creator or admin only) | Creator | ~0.006 |
| quorum | Check current quorum percentage | None | ~0.001 |
| get_proposal | Query proposal details and vote tallies | None | ~0.001 |
| withdraw_treasury | Move funds per governance approval | DAO | ~0.014 |
Vote weight proportional to governance tokens locked
COREDelegate power without transferring tokens
SOCIALMandatory delay before execution for safety
SAFETY10% participation threshold to pass proposals
GOVERNANCEOn-chain treasury controlled by DAO votes
FINANCEAll votes and executions emit on-chain events
AUDIT| Function | Description | Auth | Gas (XLM) |
|---|---|---|---|
| deposit | Send tokens to vault custody | Any | ~0.008 |
| propose_withdrawal | Create multi-sig withdrawal request | Signer | ~0.016 |
| approve | Sign/approve a pending withdrawal | Signer | ~0.010 |
| execute | Execute after threshold + timelock | Any | ~0.014 |
| cancel | Cancel a pending withdrawal | Signer | ~0.006 |
| balance | Query vault holdings for a token | None | ~0.001 |
| get_tx | Query withdrawal request details | None | ~0.001 |
| update_signers | Add/remove vault signers (multi-sig) | Threshold | ~0.018 |
Configurable M-of-N threshold for all withdrawals
SECURITY24-hour delay after approval before execution
CRITICALConfigurable daily withdrawal caps per token
LIMITAny signer can cancel during timelock period
SAFETYHold XLM, USDC, wETH, wBTC and any SEP-41
FLEXIBLEEvery deposit, approval, and execution on-chain
AUDIT| Function | Description | Auth | Gas (XLM) |
|---|---|---|---|
| create_pool | Initialize a new token pair pool | Admin | ~0.018 |
| add_liquidity | Deposit tokens, receive LP shares | User | ~0.014 |
| remove_liquidity | Burn LP shares, withdraw tokens | User | ~0.012 |
| swap | Exchange one token for another | User | ~0.010 |
| get_quote | Preview swap output (read-only) | None | ~0.001 |
| get_reserves | Query pool reserves | None | ~0.001 |
| get_price | Current spot price of pair | None | ~0.001 |
| collect_fees | Withdraw accrued protocol fees | Admin | ~0.008 |
Constant product market maker for trustless swaps
COREEarn swap fees proportional to your liquidity
YIELDmin_out parameter prevents sandwich attacks
SAFETYAll-or-nothing execution in single transaction
ATOMIC0.05% stablecoins, 0.3% standard, 1% exotic
FLEXIBLEQuery swap output before executing
PREVIEW| Function | Description | Auth | Gas (XLM) |
|---|---|---|---|
| stake | Lock tokens with optional time boost | User | ~0.014 |
| unstake | Withdraw after lock period expires | User | ~0.012 |
| compound | Reinvest rewards into position | User | ~0.010 |
| claim_rewards | Withdraw accrued rewards to wallet | User | ~0.010 |
| pending_rewards | Read-only: check unclaimed rewards | None | ~0.001 |
| get_position | Query user's stake details | None | ~0.001 |
| get_pool_info | Query pool TVL, APY, totals | None | ~0.001 |
| set_rewards | Admin: update reward rate per ledger | Admin | ~0.008 |
Up to 2.5x rewards for longer lock periods
BOOSTReinvest rewards automatically each epoch
YIELDRewards accumulate every 5-second ledger close
PRECISIONHarvest rewards without touching principal
FLEXIBLEOn-chain lock prevents early withdrawal
SAFETYPool rewards and positions fully on-chain
AUDIT