Skip to content

Commit

Permalink
Merge pull request #359 from smartcontractkit/feat/BCI-2027-multisig-…
Browse files Browse the repository at this point in the history
…cairo-tests

[BCI 2027: Adds multisig cairo tests
  • Loading branch information
archseer authored Feb 19, 2024
2 parents 9d6d994 + f9153e4 commit 00cac1d
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 163 deletions.
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,6 @@ test-integration-soak-ci:
test-integration-contracts: build-ts env-devnet-hardhat
echo "Tests currently broken because of starknet-hardhat-plugin"
exit 1
cd packages-ts/integration-multisig/ && \
yarn test
cd packages-ts/starknet/ && \
yarn test

Expand Down
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');
}

41 changes: 0 additions & 41 deletions packages-ts/integration-multisig/hardhat.config.ts

This file was deleted.

24 changes: 0 additions & 24 deletions packages-ts/integration-multisig/package.json

This file was deleted.

Loading

0 comments on commit 00cac1d

Please sign in to comment.