Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
20 changes: 20 additions & 0 deletions .github/workflows/contracts-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,26 @@ on:
- cron: '0 8 * * 1' # Every Monday at 08:00 UTC

jobs:
fmt:
name: cargo fmt --check
runs-on: ubuntu-latest

defaults:
run:
working-directory: contracts

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Rust toolchain (rustfmt)
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt

- name: cargo fmt --all --check
run: cargo fmt --all -- --check

test-and-build:
name: cargo test + build (wasm32)
runs-on: ubuntu-latest
Expand Down
13 changes: 2 additions & 11 deletions contracts/contracts/proposals/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ impl ProposalsContract {
amount,
};


env.storage()
.instance()
.set(&DataKey::Proposal(id), &proposal);
Expand All @@ -111,7 +110,6 @@ impl ProposalsContract {
},
);


id
}

Expand Down Expand Up @@ -234,12 +232,9 @@ impl ProposalsContract {
panic!("proposal not approved");
}


// Verify caller is a treasury member.
let treasury_client = crate::treasury_interface::TreasuryClient::new(
&env,
&proposal.treasury,
);
let treasury_client =
crate::treasury_interface::TreasuryClient::new(&env, &proposal.treasury);

if !treasury_client.is_member(&caller.clone()) {
panic!("caller is not a treasury member");
Expand All @@ -258,7 +253,6 @@ impl ProposalsContract {
&proposal.amount,
);


// Update proposal status.
proposal.status = ProposalStatus::Executed;
env.storage()
Expand All @@ -273,11 +267,8 @@ impl ProposalsContract {
executor: caller,
},
);

}



pub fn get_proposal(env: Env, proposal_id: u64) -> Proposal {
Self::load_proposal(&env, proposal_id)
}
Expand Down
2 changes: 0 additions & 2 deletions contracts/contracts/proposals/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ pub struct Proposal {
pub amount: i128,
}


// ── Events ───────────────────────────────────────────────────────────────────

#[contracttype]
Expand All @@ -53,7 +52,6 @@ pub struct ProposalCreatedEvent {
pub amount: i128,
}


#[contracttype]
#[derive(Clone)]
pub struct VoteCastEvent {
Expand Down
62 changes: 27 additions & 35 deletions contracts/contracts/proposals/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use soroban_sdk::testutils::Address as _;
use soroban_sdk::testutils::Ledger;
use soroban_sdk::{Env, String};


mod mock_token {
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env};

Expand Down Expand Up @@ -44,9 +43,7 @@ mod mock_token {
.set(&from_key, &(from_bal - amount));

let to_bal: i128 = env.storage().persistent().get(&to_key).unwrap_or(0);
env.storage()
.persistent()
.set(&to_key, &(to_bal + amount));
env.storage().persistent().set(&to_key, &(to_bal + amount));
}

pub fn balance(env: Env, id: Address) -> i128 {
Expand All @@ -61,10 +58,10 @@ mod mock_token {
use mock_token::MockTokenClient;

fn advance_time(env: &Env, seconds: u64) {
env.ledger().set_timestamp(env.ledger().timestamp() + seconds);
env.ledger()
.set_timestamp(env.ledger().timestamp() + seconds);
}


fn setup(
env: &Env,
) -> (
Expand All @@ -73,8 +70,7 @@ fn setup(
Address, // alice
Address, // bob
Address, // carol
group_treasury::GroupTreasuryContractClient<'static>,

group_treasury::GroupTreasuryContractClient<'static>,
Address, // treasury_admin
Address, // treasury_member
Address, // token_id
Expand All @@ -101,18 +97,12 @@ group_treasury::GroupTreasuryContractClient<'static>,
token.mint(&treasury_member, &1_000_000);

let treasury_addr = env.register(group_treasury::GroupTreasuryContract, ());
let treasury =
group_treasury::GroupTreasuryContractClient::new(env, &treasury_addr);
let treasury = group_treasury::GroupTreasuryContractClient::new(env, &treasury_addr);
treasury.initialize(&treasury_admin, &token_id);
treasury.add_member(&treasury_member);

// Deposit into treasury so `execute_withdraw` has something to withdraw.
token.transfer(
env.clone(),
&treasury_member,
&treasury_addr,
&0,
);
token.transfer(env.clone(), &treasury_member, &treasury_addr, &0);

// easier: call deposit, which also calls TokenClient::transfer from `from` to treasury
treasury.deposit(&treasury_member, &token_id, &500);
Expand Down Expand Up @@ -161,14 +151,10 @@ fn create_then_vote_then_pass_then_execute_happy_path() {
setup(&env);

let id = create_proposal_in(
&env,
&client,
&alice,
1_000,
&env, &client, &alice, 1_000,
&_m, // dummy treasury address for happy path; execute_withdraw not used here
&_m, // dummy token
&alice,
1,
&alice, 1,
);

client.vote(&alice, &id, &true);
Expand Down Expand Up @@ -203,7 +189,8 @@ fn finalize_with_more_no_votes_rejects() {
#[test]
fn finalize_with_a_tie_rejects() {
let env = Env::default();
let (client, _proposals_admin, alice, bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 500, &m, &token_id, &alice, 1);
client.vote(&alice, &id, &true);
Expand All @@ -216,7 +203,8 @@ fn finalize_with_a_tie_rejects() {
#[test]
fn finalize_with_zero_votes_rejects() {
let env = Env::default();
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 500, &m, &token_id, &alice, 1);
advance_time(&env, 501);
Expand All @@ -228,7 +216,8 @@ fn finalize_with_zero_votes_rejects() {
#[should_panic(expected = "cannot finalize before expiry")]
fn finalize_before_expiry_panics() {
let env = Env::default();
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 1_000, &m, &token_id, &alice, 1);
client.finalize_proposal(&id);
Expand All @@ -238,7 +227,8 @@ fn finalize_before_expiry_panics() {
#[should_panic(expected = "proposal already finalized")]
fn finalize_twice_panics() {
let env = Env::default();
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 500, &m, &token_id, &alice, 1);

Expand All @@ -251,7 +241,8 @@ fn finalize_twice_panics() {
#[should_panic(expected = "proposal is not in Passed state")]
fn execute_when_rejected_panics() {
let env = Env::default();
let (client, _proposals_admin, alice, bob, carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, bob, carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 500, &m, &token_id, &alice, 1);
client.vote(&alice, &id, &false);
Expand All @@ -267,7 +258,8 @@ fn execute_when_rejected_panics() {
#[should_panic(expected = "proposal is not in Passed state")]
fn execute_when_still_active_panics() {
let env = Env::default();
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 1_000, &m, &token_id, &alice, 1);
client.execute_proposal(&alice, &id);
Expand All @@ -277,7 +269,8 @@ fn execute_when_still_active_panics() {
#[should_panic(expected = "voting window has closed")]
fn vote_after_expiry_panics() {
let env = Env::default();
let (client, _proposals_admin, alice, bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 500, &m, &token_id, &alice, 1);
advance_time(&env, 600);
Expand All @@ -288,7 +281,8 @@ fn vote_after_expiry_panics() {
#[should_panic(expected = "voter has already voted")]
fn double_vote_panics() {
let env = Env::default();
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let id = create_proposal_in(&env, &client, &alice, 500, &m, &token_id, &alice, 1);
client.vote(&alice, &id, &true);
Expand All @@ -299,7 +293,8 @@ fn double_vote_panics() {
#[should_panic(expected = "expires_at must be in the future")]
fn create_with_past_expiry_panics() {
let env = Env::default();
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) = setup(&env);
let (client, _proposals_admin, alice, _bob, _carol, _treasury, _tadmin, m, token_id) =
setup(&env);

let desc = String::from_str(&env, "x");
client.create_proposal(
Expand Down Expand Up @@ -369,7 +364,6 @@ fn execute_withdraw_already_executed_panics() {

client.execute_withdraw(&treasury_member, &id);
client.execute_withdraw(&treasury_member, &id);

}

#[test]
Expand Down Expand Up @@ -415,8 +409,7 @@ fn execute_withdraw_reduces_balance() {
#[should_panic(expected = "caller is not a treasury member")]
fn execute_withdraw_non_member_panics() {
let env = Env::default();
let (client, _padmin, alice, _bob, _carol, treasury, _tadmin, _member, token_id) =
setup(&env);
let (client, _padmin, alice, _bob, _carol, treasury, _tadmin, _member, token_id) = setup(&env);

let treasury_addr = treasury.address();
let to = alice.clone();
Expand All @@ -438,4 +431,3 @@ fn execute_withdraw_non_member_panics() {
// alice is not a treasury member
client.execute_withdraw(&alice, &id);
}