Skip to content

Commit

Permalink
adds recursive multisig cairo tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-de-leon-cll committed Feb 14, 2024
1 parent 3bbc56c commit 168491a
Showing 1 changed file with 293 additions and 3 deletions.
296 changes: 293 additions & 3 deletions contracts/src/tests/test_multisig.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use chainlink::multisig::IMultisigDispatcherTrait;
use core::traits::Into;
use starknet::class_hash_const;
use starknet::contract_address_const;
use starknet::syscalls::deploy_syscall;
Expand All @@ -13,6 +15,7 @@ use traits::TryInto;
use chainlink::multisig::assert_unique_values;
use chainlink::multisig::Multisig;
use chainlink::multisig::Multisig::{MultisigImpl, UpgradeableImpl};
use chainlink::multisig::{IMultisigDispatcher};

#[starknet::contract]
mod MultisigTest {
Expand All @@ -27,9 +30,6 @@ mod MultisigTest {
}
}

// TODO: test set_threshold with recursive call
// TODO: test set_signers with recursive call
// TODO: test set_signers_and_thershold with recursive call

fn STATE() -> Multisig::ContractState {
Multisig::contract_state_for_testing()
Expand Down Expand Up @@ -434,3 +434,293 @@ fn test_execute_after_set_threshold() {
set_caller_address(signer1);
MultisigImpl::execute_transaction(ref state, nonce: 0);
}

// test set_threshold (non-recursive)
#[test]
fn test_set_threshold() {
let s1 = contract_address_const::<1>();
let s2 = contract_address_const::<2>();
let s3 = contract_address_const::<3>();
let signers = array![s1, s2, s3];
let init_threshold: usize = 3;
let new_threshold: usize = 2;

let mut deploy_calldata = ArrayTrait::new();
Serde::serialize(@signers, ref deploy_calldata);
Serde::serialize(@init_threshold, ref deploy_calldata);
let (multisig_address, _) = deploy_syscall(
Multisig::TEST_CLASS_HASH.try_into().unwrap(), 0, deploy_calldata.span(), false
)
.unwrap();

let multisig = IMultisigDispatcher { contract_address: multisig_address };
assert(multisig.get_threshold() == init_threshold, 'invalid init threshold');
set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig.set_threshold(new_threshold);
assert(multisig.get_threshold() == new_threshold, 'threshold was not updated');
}

// test set_threshold with recursive call
#[test]
fn test_recursive_set_threshold() {
// Defines helper variables
let s1 = contract_address_const::<1>();
let s2 = contract_address_const::<2>();
let signers = array![s1, s2];
let init_threshold: usize = 2;
let new_threshold: usize = 1;

// Deploys the contract
let mut deploy_calldata = ArrayTrait::new();
Serde::serialize(@signers, ref deploy_calldata);
Serde::serialize(@init_threshold, ref deploy_calldata);
let (multisig_address, _) = deploy_syscall(
Multisig::TEST_CLASS_HASH.try_into().unwrap(), 0, deploy_calldata.span(), false
)
.unwrap();

// Gets a dispatcher (so we can call methods on the deployed contract)
let multisig = IMultisigDispatcher { contract_address: multisig_address };

// Checks that the threshold was correctly initialized on deployment
assert(multisig.get_threshold() == init_threshold, 'invalid init threshold');

// Recursive call occurs here - this code proposes a transaction to the
// multisig contract that calls the set_threshold function on the multisig
// contract.
let mut set_threshold_calldata = ArrayTrait::new();
Serde::serialize(@new_threshold, ref set_threshold_calldata);
set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig
.submit_transaction(multisig_address, selector!("set_threshold"), set_threshold_calldata);

// Signer 1 confirms the transaction
set_caller_address(s1);
set_contract_address(s1);
multisig.confirm_transaction(0);

// Signer 2 confirms the transaction
set_caller_address(s2);
set_contract_address(s2);
multisig.confirm_transaction(0);

// Once we have enough confirmations, we execute the transaction
set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig.execute_transaction(0);

// Now we check that the threshold was actually updated
assert(multisig.get_threshold() == new_threshold, 'threshold was not updated');
}

// test set_signers (non-recursive)
#[test]
fn test_set_signers() {
let s1 = contract_address_const::<1>();
let s2 = contract_address_const::<2>();
let init_signers = array![s1, s2];
let new_signers = array![s1];
let threshold: usize = 2;

let mut deploy_calldata = ArrayTrait::new();
Serde::serialize(@init_signers, ref deploy_calldata);
Serde::serialize(@threshold, ref deploy_calldata);
let (multisig_address, _) = deploy_syscall(
Multisig::TEST_CLASS_HASH.try_into().unwrap(), 0, deploy_calldata.span(), false
)
.unwrap();

let multisig = IMultisigDispatcher { contract_address: multisig_address };

let returned_signers = multisig.get_signers();
assert(returned_signers.len() == 2, 'should match signers length');
assert(*returned_signers.at(0) == s1, 'should match signer 1');
assert(*returned_signers.at(1) == s2, 'should match signer 2');
assert(multisig.get_threshold() == 2, 'wrong init threshold');

set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig.set_signers(new_signers);

let updated_signers = multisig.get_signers();
assert(updated_signers.len() == 1, 'should match signers length');
assert(*updated_signers.at(0) == s1, 'should match signer 1');
assert(multisig.get_threshold() == 1, 'threshold not updated');
}

// test set_signers with recursive call
#[test]
fn test_recursive_set_signers() {
// Defines helper variables
let s1 = contract_address_const::<1>();
let s2 = contract_address_const::<2>();
let init_signers = array![s1, s2];
let new_signers = array![s1];
let init_threshold: usize = 2;

// Deploys the contract
let mut deploy_calldata = ArrayTrait::new();
Serde::serialize(@init_signers, ref deploy_calldata);
Serde::serialize(@init_threshold, ref deploy_calldata);
let (multisig_address, _) = deploy_syscall(
Multisig::TEST_CLASS_HASH.try_into().unwrap(), 0, deploy_calldata.span(), false
)
.unwrap();

// Gets a dispatcher (so we can call methods on the deployed contract)
let multisig = IMultisigDispatcher { contract_address: multisig_address };

// Checks that the signers were correctly initialized on deployment
let returned_signers = multisig.get_signers();
assert(returned_signers.len() == 2, 'should match signers length');
assert(*returned_signers.at(0) == s1, 'should match signer 1');
assert(*returned_signers.at(1) == s2, 'should match signer 2');
assert(multisig.get_threshold() == 2, 'wrong init threshold');

// Recursive call occurs here - this code proposes a transaction to the
// multisig contract that calls the set_signers function on the multisig
// contract.
let mut set_signers_calldata = ArrayTrait::new();
Serde::serialize(@new_signers, ref set_signers_calldata);
set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig.submit_transaction(multisig_address, selector!("set_signers"), set_signers_calldata);

// Signer 1 confirms the transaction
set_caller_address(s1);
set_contract_address(s1);
multisig.confirm_transaction(0);

// Signer 2 confirms the transaction
set_caller_address(s2);
set_contract_address(s2);
multisig.confirm_transaction(0);

// Once we have enough confirmations, we execute the transaction
set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig.execute_transaction(0);

// Now we check that the signers were actually updated
let updated_signers = multisig.get_signers();
assert(updated_signers.len() == 1, 'should match signers length');
assert(*updated_signers.at(0) == s1, 'should match signer 1');
assert(multisig.get_threshold() == 1, 'wrong threshold');
}

// test set_signers_and_threshold (non-recursive)
#[test]
fn test_set_signers_and_threshold() {
let s1 = contract_address_const::<1>();
let s2 = contract_address_const::<2>();
let s3 = contract_address_const::<3>();
let init_signers = array![s1, s2, s3];
let new_signers = array![s1, s2];
let init_threshold: usize = 3;
let new_threshold: usize = 1;

let mut deploy_calldata = ArrayTrait::new();
Serde::serialize(@init_signers, ref deploy_calldata);
Serde::serialize(@init_threshold, ref deploy_calldata);
let (multisig_address, _) = deploy_syscall(
Multisig::TEST_CLASS_HASH.try_into().unwrap(), 0, deploy_calldata.span(), false
)
.unwrap();

let multisig = IMultisigDispatcher { contract_address: multisig_address };

let returned_signers = multisig.get_signers();
assert(returned_signers.len() == 3, 'should match signers length');
assert(*returned_signers.at(0) == s1, 'should match signer 1');
assert(*returned_signers.at(1) == s2, 'should match signer 2');
assert(*returned_signers.at(2) == s3, 'should match signer 3');
assert(multisig.get_threshold() == init_threshold, 'wrong init threshold');

set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig.set_signers_and_threshold(new_signers, new_threshold);

let updated_signers = multisig.get_signers();
assert(updated_signers.len() == 2, 'should match signers length');
assert(*updated_signers.at(0) == s1, 'should match signer 1');
assert(*updated_signers.at(1) == s2, 'should match signer 2');
assert(multisig.get_threshold() == new_threshold, 'threshold not updated');
}

// test set_signers_and_threshold with recursive call
#[test]
fn test_recursive_set_signers_and_threshold() {
// Defines helper variables
let s1 = contract_address_const::<1>();
let s2 = contract_address_const::<2>();
let s3 = contract_address_const::<3>();
let init_signers = array![s1, s2, s3];
let new_signers = array![s1, s2];
let init_threshold: usize = 3;
let new_threshold: usize = 1;

// Deploys the contract
let mut deploy_calldata = ArrayTrait::new();
Serde::serialize(@init_signers, ref deploy_calldata);
Serde::serialize(@init_threshold, ref deploy_calldata);
let (multisig_address, _) = deploy_syscall(
Multisig::TEST_CLASS_HASH.try_into().unwrap(), 0, deploy_calldata.span(), false
)
.unwrap();

// Gets a dispatcher (so we can call methods on the deployed contract)
let multisig = IMultisigDispatcher { contract_address: multisig_address };

// Checks that the initial state is correct
let returned_signers = multisig.get_signers();
assert(returned_signers.len() == 3, 'should match signers length');
assert(*returned_signers.at(0) == s1, 'should match signer 1');
assert(*returned_signers.at(1) == s2, 'should match signer 2');
assert(*returned_signers.at(2) == s3, 'should match signer 3');
assert(multisig.get_threshold() == 3, 'wrong init threshold');

// Recursive call occurs here - this code proposes a transaction to the
// multisig contract that calls the set_signers_and_threshold function
// on the multisig contract.
let mut set_signers_and_threshold_calldata = ArrayTrait::new();
Serde::serialize(@new_signers, ref set_signers_and_threshold_calldata);
Serde::serialize(@new_threshold, ref set_signers_and_threshold_calldata);
set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig
.submit_transaction(
multisig_address,
selector!("set_signers_and_threshold"),
set_signers_and_threshold_calldata
);

// Signer 1 confirms the transaction
set_caller_address(s1);
set_contract_address(s1);
multisig.confirm_transaction(0);

// Signer 2 confirms the transaction
set_caller_address(s2);
set_contract_address(s2);
multisig.confirm_transaction(0);

// Signer 3 confirms the transaction
set_caller_address(s3);
set_contract_address(s3);
multisig.confirm_transaction(0);

// Once we have enough confirmations, we execute the transaction
set_caller_address(multisig_address);
set_contract_address(multisig_address);
multisig.execute_transaction(0);

// Now we check that the signers were actually updated
let updated_signers = multisig.get_signers();
assert(updated_signers.len() == 2, 'should match signers length');
assert(*updated_signers.at(0) == s1, 'should match signer 1');
assert(*updated_signers.at(1) == s2, 'should match signer 2');
assert(multisig.get_threshold() == 1, 'wrong threshold');
}

0 comments on commit 168491a

Please sign in to comment.