Skip to content

Commit ef406f4

Browse files
committed
Test multisig operations with threshold < 2
1 parent 9a65976 commit ef406f4

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

packages/shared/src/multisig.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,126 @@ async function wrongTimepointTest<
16581658
assert(client.api.errors.multisig.WrongTimepoint.is(dispatchError2.asModule))
16591659
}
16601660

1661+
/**
1662+
* Test that multisig cancellation with threshold < 2 fails.
1663+
*
1664+
* 1. Alice attempts to cancel a multisig with threshold = 1
1665+
* 2. Verify that the transaction fails with the appropriate error
1666+
*/
1667+
async function minimumThresholdCancelTest<
1668+
TCustom extends Record<string, unknown> | undefined,
1669+
TInitStorages extends Record<string, Record<string, any>> | undefined,
1670+
>(chain: Chain<TCustom, TInitStorages>) {
1671+
const [client] = await setupNetworks(chain)
1672+
1673+
const alice = defaultAccountsSr25519.alice
1674+
const bob = defaultAccountsSr25519.bob
1675+
const dave = defaultAccountsSr25519.dave
1676+
1677+
// Fund test accounts
1678+
await client.dev.setStorage({
1679+
System: {
1680+
account: [[[bob.address], { providers: 1, data: { free: 1000e10 } }]],
1681+
},
1682+
})
1683+
1684+
// Create a simple call to transfer funds to Dave
1685+
const transferAmount = 100e10
1686+
const transferCall = client.api.tx.balances.transferKeepAlive(dave.address, transferAmount)
1687+
1688+
// Alice attempts to cancel a multisig with threshold = 1 (invalid)
1689+
const threshold = 1 // Invalid threshold - should be >= 2
1690+
const otherSignatories = [bob.address]
1691+
const callHash = transferCall.method.hash
1692+
1693+
const cancelTx = client.api.tx.multisig.cancelAsMulti(
1694+
threshold,
1695+
otherSignatories,
1696+
{
1697+
height: 1,
1698+
index: 0,
1699+
},
1700+
callHash,
1701+
)
1702+
1703+
await sendTransaction(cancelTx.signAsync(alice))
1704+
1705+
await client.dev.newBlock()
1706+
1707+
// Check for ExtrinsicFailed event
1708+
const events = await client.api.query.system.events()
1709+
1710+
const [ev] = events.filter((record) => {
1711+
const { event } = record
1712+
return event.section === 'system' && event.method === 'ExtrinsicFailed'
1713+
})
1714+
1715+
assert(client.api.events.system.ExtrinsicFailed.is(ev.event))
1716+
const dispatchError = ev.event.data.dispatchError
1717+
1718+
assert(dispatchError.isModule)
1719+
assert(client.api.errors.multisig.MinimumThreshold.is(dispatchError.asModule))
1720+
}
1721+
1722+
/**
1723+
* Test that as_multi with threshold < 2 fails.
1724+
*
1725+
* 1. Alice attempts to create a multisig with threshold = 1 using as_multi
1726+
* 2. Verify that the transaction fails with the appropriate error
1727+
*/
1728+
async function minimumThresholdAsMultiTest<
1729+
TCustom extends Record<string, unknown> | undefined,
1730+
TInitStorages extends Record<string, Record<string, any>> | undefined,
1731+
>(chain: Chain<TCustom, TInitStorages>) {
1732+
const [client] = await setupNetworks(chain)
1733+
1734+
const alice = defaultAccountsSr25519.alice
1735+
const bob = defaultAccountsSr25519.bob
1736+
const dave = defaultAccountsSr25519.dave
1737+
1738+
// Fund test accounts
1739+
await client.dev.setStorage({
1740+
System: {
1741+
account: [[[bob.address], { providers: 1, data: { free: 1000e10 } }]],
1742+
},
1743+
})
1744+
1745+
// Create a simple call to transfer funds to Dave
1746+
const transferAmount = 100e10
1747+
const transferCall = client.api.tx.balances.transferKeepAlive(dave.address, transferAmount)
1748+
1749+
// Alice attempts to create a multisig with threshold = 1 (invalid)
1750+
const threshold = 1 // Invalid threshold - should be >= 2
1751+
const otherSignatories = [bob.address]
1752+
const maxWeight = { refTime: 1000000000, proofSize: 1000000 }
1753+
1754+
const asMultiTx = client.api.tx.multisig.asMulti(
1755+
threshold,
1756+
otherSignatories,
1757+
null, // No timepoint for first approval
1758+
transferCall.method.toHex(),
1759+
maxWeight,
1760+
)
1761+
1762+
await sendTransaction(asMultiTx.signAsync(alice))
1763+
1764+
await client.dev.newBlock()
1765+
1766+
// Check for ExtrinsicFailed event
1767+
const events = await client.api.query.system.events()
1768+
1769+
const [ev] = events.filter((record) => {
1770+
const { event } = record
1771+
return event.section === 'system' && event.method === 'ExtrinsicFailed'
1772+
})
1773+
1774+
assert(client.api.events.system.ExtrinsicFailed.is(ev.event))
1775+
const dispatchError = ev.event.data.dispatchError
1776+
1777+
assert(dispatchError.isModule)
1778+
assert(client.api.errors.multisig.MinimumThreshold.is(dispatchError.asModule))
1779+
}
1780+
16611781
export function multisigE2ETests<
16621782
TCustom extends Record<string, unknown> | undefined,
16631783
TInitStorages extends Record<string, Record<string, any>> | undefined,
@@ -1726,5 +1846,13 @@ export function multisigE2ETests<
17261846
test('approval with wrong timepoint fails', async () => {
17271847
await wrongTimepointTest(chain)
17281848
})
1849+
1850+
test('multisig cancellation with threshold < 2 fails', async () => {
1851+
await minimumThresholdCancelTest(chain)
1852+
})
1853+
1854+
test('creating a multisig with threshold < 2 fails', async () => {
1855+
await minimumThresholdAsMultiTest(chain)
1856+
})
17291857
})
17301858
}

0 commit comments

Comments
 (0)