Skip to content

Commit a0519f0

Browse files
committed
✨ feat(shared,demos): use cohort multisig address instead of first signer
- Add getCohortMultisigAddress() method to SigningCoordinatorAgent - Calls getSigningCoordinatorChild(chainId) to get child contract - Uses cohortMultisigs(cohortId) mapping to get actual multisig address - Update taco-mdt-aa-signing demo to use cohort multisig address - Replace signers[0] placeholder with proper deployed multisig contract - Add console log showing cohort multisig address being used - Update documentation to reflect multisig vs individual signer usage Addresses Derek's feedback in PR nucypher#693 to use the deployed cohort multisig contract (e.g., 0x857949079dB532301157Eb7Fb5AEC3398043A186) instead of individual signer addresses for ERC-1271 compatibility. Successfully tested - demo retrieves correct multisig and executes transactions.
1 parent 6c7c21b commit a0519f0

File tree

5 files changed

+137
-54
lines changed

5 files changed

+137
-54
lines changed

demos/taco-mdt-aa-signing/src/index.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,19 @@ async function createTacoSmartAccount(
5252
);
5353
const signers = participants.map((p) => p.operator as Address).sort();
5454

55-
// Create a TACo account using the first signer as placeholder address
56-
// This satisfies MetaMask's signatory requirement without using a local wallet
57-
const tacoAccount = createViemTacoAccount(signers[0]);
55+
// Get the cohort's actual multisig contract address
56+
const cohortMultisigAddress =
57+
await SigningCoordinatorAgent.getCohortMultisigAddress(
58+
provider,
59+
TACO_DOMAIN,
60+
COHORT_ID,
61+
SEPOLIA_CHAIN_ID,
62+
);
63+
64+
// Create a TACo account using the cohort's multisig address
65+
// This satisfies MetaMask's signatory requirement and uses the proper cohort multisig
66+
const tacoAccount = createViemTacoAccount(cohortMultisigAddress as Address);
67+
console.log(`🎯 Using cohort multisig: ${cohortMultisigAddress}`);
5868

5969
const smartAccount = await toMetaMaskSmartAccount({
6070
// eslint-disable-next-line @typescript-eslint/no-explicit-any

demos/taco-mdt-aa-signing/src/taco-account.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { toAccount } from 'viem/accounts';
44
/**
55
* Creates a minimal Viem Account that serves as a placeholder for the MetaMask Smart Account.
66
* This account is never actually used for signing - all real signing happens through the TACo network
7-
* via the separate signUserOp function.
7+
* via the separate signUserOpWithTaco function.
88
*
9-
* @param cohortAddress - Address of a TACo cohort participant (used as the account address)
9+
* @param cohortAddress - Address of the TACo cohort's multisig contract (used as the account address)
1010
* @returns A Viem Account with stub implementations
1111
*/
1212
export function createViemTacoAccount(cohortAddress: Address) {
@@ -28,4 +28,3 @@ export function createViemTacoAccount(cohortAddress: Address) {
2828
},
2929
});
3030
}
31-

packages/shared/src/contracts/agents/signing-coordinator.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,32 @@ export class SigningCoordinatorAgent {
7373
);
7474
}
7575

76+
public static async getCohortMultisigAddress(
77+
provider: ethers.providers.Provider,
78+
domain: Domain,
79+
cohortId: number,
80+
chainId: number,
81+
): Promise<string> {
82+
const coordinator = await this.connectReadOnly(provider, domain);
83+
84+
// Get the SigningCoordinatorChild contract address for this chain
85+
const childAddress = await coordinator.getSigningCoordinatorChild(chainId);
86+
87+
// Create a contract instance for the child (using generic Contract interface)
88+
const childContract = new ethers.Contract(
89+
childAddress,
90+
[
91+
// ABI for the cohortMultisigs function
92+
'function cohortMultisigs(uint32) view returns (address)',
93+
],
94+
provider,
95+
);
96+
97+
// Get the multisig address for this cohort
98+
const multisigAddress = await childContract.cohortMultisigs(cohortId);
99+
return multisigAddress;
100+
}
101+
76102
private static async connectReadOnly(
77103
provider: ethers.providers.Provider,
78104
domain: Domain,

packages/shared/src/contracts/ethers-typechain/SigningCoordinator.ts

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,16 @@ export interface SigningCoordinatorInterface extends utils.Interface {
5353
'defaultAdminDelay()': FunctionFragment;
5454
'defaultAdminDelayIncreaseWait()': FunctionFragment;
5555
'deployAdditionalChainForSigningMultisig(uint256,uint32)': FunctionFragment;
56+
'extendSigningCohortDuration(uint32,uint32)': FunctionFragment;
5657
'getChains(uint32)': FunctionFragment;
57-
'getCondition(uint32,uint256)': FunctionFragment;
5858
'getRoleAdmin(bytes32)': FunctionFragment;
5959
'getSigner(uint32,address)': FunctionFragment;
6060
'getSigners(uint32)': FunctionFragment;
6161
'getSigningCohortConditions(uint32,uint256)': FunctionFragment;
6262
'getSigningCohortDataHash(uint32)': FunctionFragment;
6363
'getSigningCohortState(uint32)': FunctionFragment;
6464
'getSigningCoordinatorChild(uint256)': FunctionFragment;
65+
'getThreshold(uint32)': FunctionFragment;
6566
'grantRole(bytes32,address)': FunctionFragment;
6667
'hasRole(bytes32,address)': FunctionFragment;
6768
'initialize(uint32,uint16,address,address)': FunctionFragment;
@@ -100,15 +101,16 @@ export interface SigningCoordinatorInterface extends utils.Interface {
100101
| 'defaultAdminDelay'
101102
| 'defaultAdminDelayIncreaseWait'
102103
| 'deployAdditionalChainForSigningMultisig'
104+
| 'extendSigningCohortDuration'
103105
| 'getChains'
104-
| 'getCondition'
105106
| 'getRoleAdmin'
106107
| 'getSigner'
107108
| 'getSigners'
108109
| 'getSigningCohortConditions'
109110
| 'getSigningCohortDataHash'
110111
| 'getSigningCohortState'
111112
| 'getSigningCoordinatorChild'
113+
| 'getThreshold'
112114
| 'grantRole'
113115
| 'hasRole'
114116
| 'initialize'
@@ -179,12 +181,12 @@ export interface SigningCoordinatorInterface extends utils.Interface {
179181
values: [BigNumberish, BigNumberish],
180182
): string;
181183
encodeFunctionData(
182-
functionFragment: 'getChains',
183-
values: [BigNumberish],
184+
functionFragment: 'extendSigningCohortDuration',
185+
values: [BigNumberish, BigNumberish],
184186
): string;
185187
encodeFunctionData(
186-
functionFragment: 'getCondition',
187-
values: [BigNumberish, BigNumberish],
188+
functionFragment: 'getChains',
189+
values: [BigNumberish],
188190
): string;
189191
encodeFunctionData(
190192
functionFragment: 'getRoleAdmin',
@@ -214,6 +216,10 @@ export interface SigningCoordinatorInterface extends utils.Interface {
214216
functionFragment: 'getSigningCoordinatorChild',
215217
values: [BigNumberish],
216218
): string;
219+
encodeFunctionData(
220+
functionFragment: 'getThreshold',
221+
values: [BigNumberish],
222+
): string;
217223
encodeFunctionData(
218224
functionFragment: 'grantRole',
219225
values: [BytesLike, string],
@@ -345,11 +351,11 @@ export interface SigningCoordinatorInterface extends utils.Interface {
345351
functionFragment: 'deployAdditionalChainForSigningMultisig',
346352
data: BytesLike,
347353
): Result;
348-
decodeFunctionResult(functionFragment: 'getChains', data: BytesLike): Result;
349354
decodeFunctionResult(
350-
functionFragment: 'getCondition',
355+
functionFragment: 'extendSigningCohortDuration',
351356
data: BytesLike,
352357
): Result;
358+
decodeFunctionResult(functionFragment: 'getChains', data: BytesLike): Result;
353359
decodeFunctionResult(
354360
functionFragment: 'getRoleAdmin',
355361
data: BytesLike,
@@ -372,6 +378,10 @@ export interface SigningCoordinatorInterface extends utils.Interface {
372378
functionFragment: 'getSigningCoordinatorChild',
373379
data: BytesLike,
374380
): Result;
381+
decodeFunctionResult(
382+
functionFragment: 'getThreshold',
383+
data: BytesLike,
384+
): Result;
375385
decodeFunctionResult(functionFragment: 'grantRole', data: BytesLike): Result;
376386
decodeFunctionResult(functionFragment: 'hasRole', data: BytesLike): Result;
377387
decodeFunctionResult(functionFragment: 'initialize', data: BytesLike): Result;
@@ -722,16 +732,16 @@ export interface SigningCoordinator extends BaseContract {
722732
overrides?: Overrides & { from?: string },
723733
): Promise<ContractTransaction>;
724734

725-
getChains(
735+
extendSigningCohortDuration(
726736
cohortId: BigNumberish,
727-
overrides?: CallOverrides,
728-
): Promise<[BigNumber[]]>;
737+
additionalDuration: BigNumberish,
738+
overrides?: Overrides & { from?: string },
739+
): Promise<ContractTransaction>;
729740

730-
getCondition(
741+
getChains(
731742
cohortId: BigNumberish,
732-
chainId: BigNumberish,
733743
overrides?: CallOverrides,
734-
): Promise<[string]>;
744+
): Promise<[BigNumber[]]>;
735745

736746
getRoleAdmin(role: BytesLike, overrides?: CallOverrides): Promise<[string]>;
737747

@@ -767,6 +777,11 @@ export interface SigningCoordinator extends BaseContract {
767777
overrides?: CallOverrides,
768778
): Promise<[string]>;
769779

780+
getThreshold(
781+
cohortId: BigNumberish,
782+
overrides?: CallOverrides,
783+
): Promise<[number]>;
784+
770785
grantRole(
771786
role: BytesLike,
772787
account: string,
@@ -926,16 +941,16 @@ export interface SigningCoordinator extends BaseContract {
926941
overrides?: Overrides & { from?: string },
927942
): Promise<ContractTransaction>;
928943

929-
getChains(
944+
extendSigningCohortDuration(
930945
cohortId: BigNumberish,
931-
overrides?: CallOverrides,
932-
): Promise<BigNumber[]>;
946+
additionalDuration: BigNumberish,
947+
overrides?: Overrides & { from?: string },
948+
): Promise<ContractTransaction>;
933949

934-
getCondition(
950+
getChains(
935951
cohortId: BigNumberish,
936-
chainId: BigNumberish,
937952
overrides?: CallOverrides,
938-
): Promise<string>;
953+
): Promise<BigNumber[]>;
939954

940955
getRoleAdmin(role: BytesLike, overrides?: CallOverrides): Promise<string>;
941956

@@ -971,6 +986,11 @@ export interface SigningCoordinator extends BaseContract {
971986
overrides?: CallOverrides,
972987
): Promise<string>;
973988

989+
getThreshold(
990+
cohortId: BigNumberish,
991+
overrides?: CallOverrides,
992+
): Promise<number>;
993+
974994
grantRole(
975995
role: BytesLike,
976996
account: string,
@@ -1126,16 +1146,16 @@ export interface SigningCoordinator extends BaseContract {
11261146
overrides?: CallOverrides,
11271147
): Promise<void>;
11281148

1129-
getChains(
1149+
extendSigningCohortDuration(
11301150
cohortId: BigNumberish,
1151+
additionalDuration: BigNumberish,
11311152
overrides?: CallOverrides,
1132-
): Promise<BigNumber[]>;
1153+
): Promise<void>;
11331154

1134-
getCondition(
1155+
getChains(
11351156
cohortId: BigNumberish,
1136-
chainId: BigNumberish,
11371157
overrides?: CallOverrides,
1138-
): Promise<string>;
1158+
): Promise<BigNumber[]>;
11391159

11401160
getRoleAdmin(role: BytesLike, overrides?: CallOverrides): Promise<string>;
11411161

@@ -1171,6 +1191,11 @@ export interface SigningCoordinator extends BaseContract {
11711191
overrides?: CallOverrides,
11721192
): Promise<string>;
11731193

1194+
getThreshold(
1195+
cohortId: BigNumberish,
1196+
overrides?: CallOverrides,
1197+
): Promise<number>;
1198+
11741199
grantRole(
11751200
role: BytesLike,
11761201
account: string,
@@ -1461,14 +1486,14 @@ export interface SigningCoordinator extends BaseContract {
14611486
overrides?: Overrides & { from?: string },
14621487
): Promise<BigNumber>;
14631488

1464-
getChains(
1489+
extendSigningCohortDuration(
14651490
cohortId: BigNumberish,
1466-
overrides?: CallOverrides,
1491+
additionalDuration: BigNumberish,
1492+
overrides?: Overrides & { from?: string },
14671493
): Promise<BigNumber>;
14681494

1469-
getCondition(
1495+
getChains(
14701496
cohortId: BigNumberish,
1471-
chainId: BigNumberish,
14721497
overrides?: CallOverrides,
14731498
): Promise<BigNumber>;
14741499

@@ -1509,6 +1534,11 @@ export interface SigningCoordinator extends BaseContract {
15091534
overrides?: CallOverrides,
15101535
): Promise<BigNumber>;
15111536

1537+
getThreshold(
1538+
cohortId: BigNumberish,
1539+
overrides?: CallOverrides,
1540+
): Promise<BigNumber>;
1541+
15121542
grantRole(
15131543
role: BytesLike,
15141544
account: string,
@@ -1659,14 +1689,14 @@ export interface SigningCoordinator extends BaseContract {
16591689
overrides?: Overrides & { from?: string },
16601690
): Promise<PopulatedTransaction>;
16611691

1662-
getChains(
1692+
extendSigningCohortDuration(
16631693
cohortId: BigNumberish,
1664-
overrides?: CallOverrides,
1694+
additionalDuration: BigNumberish,
1695+
overrides?: Overrides & { from?: string },
16651696
): Promise<PopulatedTransaction>;
16661697

1667-
getCondition(
1698+
getChains(
16681699
cohortId: BigNumberish,
1669-
chainId: BigNumberish,
16701700
overrides?: CallOverrides,
16711701
): Promise<PopulatedTransaction>;
16721702

@@ -1707,6 +1737,11 @@ export interface SigningCoordinator extends BaseContract {
17071737
overrides?: CallOverrides,
17081738
): Promise<PopulatedTransaction>;
17091739

1740+
getThreshold(
1741+
cohortId: BigNumberish,
1742+
overrides?: CallOverrides,
1743+
): Promise<PopulatedTransaction>;
1744+
17101745
grantRole(
17111746
role: BytesLike,
17121747
account: string,

0 commit comments

Comments
 (0)