Skip to content

Commit

Permalink
add test for multisig join
Browse files Browse the repository at this point in the history
  • Loading branch information
daviddm committed Feb 26, 2024
1 parent aadfce0 commit 4b7bd58
Show file tree
Hide file tree
Showing 3 changed files with 282 additions and 19 deletions.
278 changes: 278 additions & 0 deletions examples/integration-scripts/multisig-join.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
import signify, { Serder, SignifyClient } from 'signify-ts';
import { resolveEnvironment } from './utils/resolve-env';
import { getOrCreateClient, getOrCreateIdentifier } from './utils/test-setup';
import {
markNotification,
waitForNotifications,
waitOperation,
} from './utils/test-util';
import assert from 'assert';

const { vleiServerUrl, url } = resolveEnvironment();

describe('multisig-join', () => {
const nameMember1 = 'member1';
const nameMember2 = 'member2';
const nameMultisig = 'multisigGroup';

let client1: SignifyClient;
let client2: SignifyClient;

beforeAll(async () => {
await signify.ready();

[client1, client2] = await Promise.all([
getOrCreateClient(),
getOrCreateClient(),
]);

await Promise.all([
createAID(client1, nameMember1, []),
createAID(client2, nameMember2, []),
]);

const [oobi1, oobi2] = await Promise.all([
client1.oobis().get(nameMember1, 'agent'),
client2.oobis().get(nameMember2, 'agent'),
]);

const opOobi1 = await client1
.oobis()
.resolve(oobi2.oobis[0], nameMember2);
const opOobi2 = await client2
.oobis()
.resolve(oobi1.oobis[0], nameMember1);
await Promise.all([
waitOperation(client1, opOobi1),
waitOperation(client2, opOobi2),
]);
});

test('should create multisig', async () => {
const [aid1, aid2] = await Promise.all([
client1.identifiers().get(nameMember1),
client2.identifiers().get(nameMember2),
]);
const states = [aid1.state, aid2.state];
const icpResult = await client1.identifiers().create(nameMultisig, {
algo: signify.Algos.group,
mhab: aid1,
isith: 1,
nsith: 1,
toad: aid1.state.b.length,
wits: aid1.state.b,
states: states,
rstates: states,
});

const createMultisig1 = await icpResult.op();

const serder = icpResult.serder;

const sigs = icpResult.sigs;
const sigers = sigs.map((sig) => new signify.Siger({ qb64: sig }));

const ims = signify.d(signify.messagize(serder, sigers));
const atc = ims.substring(serder.size);
const embeds = {
icp: [serder, atc],
};

const smids = [aid2.state.i];
const recipients = [aid2.state.i];

await client1
.exchanges()
.send(
nameMember1,
nameMultisig,
aid1,
'/multisig/icp',
{ gid: serder.pre, smids: smids, rmids: smids },
embeds,
recipients
);

const msgSaid = await waitAndMarkNotification(client2, '/multisig/icp');

const response = await client2.groups().getRequest(msgSaid);
const icp = response[0].exn.e.icp;

const icpResult2 = await client2.identifiers().create(nameMultisig, {
algo: signify.Algos.group,
mhab: aid2,
isith: icp.kt,
nsith: icp.nt,
toad: parseInt(icp.bt),
wits: icp.b,
states,
rstates: states,
});
const createMultisig2 = await icpResult2.op();

const [createResult1, createResult2] = await Promise.all([
waitOperation(client1, createMultisig1),
waitOperation(client2, createMultisig2),
]);

assert.equal(createResult1.response.k[0], aid1.state.k[0]);
assert.equal(createResult1.response.k[1], aid2.state.k[0]);
assert.equal(createResult2.response.k[0], aid1.state.k[0]);
assert.equal(createResult2.response.k[1], aid2.state.k[0]);

const members = await client1.identifiers().members(nameMultisig);
const signing = members.signing;
const eid1 = Object.keys(signing[0].ends.agent)[0];

const endRoleOperation = await client1
.identifiers()
.addEndRole(nameMultisig, 'agent', eid1);

await waitOperation(client1, await endRoleOperation.op());
});

test('should add member3 to multisig', async () => {
const nameMember3 = 'member3';
const client3 = await getOrCreateClient();

const aid3 = await createAID(client3, nameMember3, []);

const [oobi1, oobi2, oobi3, oobi4] = await Promise.all([
client1.oobis().get(nameMember1, 'agent'),
client2.oobis().get(nameMember2, 'agent'),
client3.oobis().get(nameMember3, 'agent'),
client1.oobis().get(nameMultisig, 'agent'),
]);

const oobiMultisig = oobi4.oobis[0].split('/agent/')[0];

const [opOobi1, opOobi2, opOobi3, opOobi4, opOobi5] = await Promise.all(
[
client1.oobis().resolve(oobi3.oobis[0], nameMember3),
client2.oobis().resolve(oobi3.oobis[0], nameMember3),
client3.oobis().resolve(oobi1.oobis[0], nameMember1),
client3.oobis().resolve(oobi2.oobis[0], nameMember2),
client3.oobis().resolve(oobiMultisig, nameMultisig),
]
);
await Promise.all([
waitOperation(client1, opOobi1),
waitOperation(client2, opOobi2),
waitOperation(client3, opOobi3),
waitOperation(client3, opOobi4),
waitOperation(client3, opOobi5),
]);

const [rotateResult1, rotateResult2] = await Promise.all([
client1.identifiers().rotate(nameMember1),
client2.identifiers().rotate(nameMember2),
]);

await Promise.all([
waitOperation(client1, await rotateResult1.op()),
waitOperation(client2, await rotateResult2.op()),
]);

const [aid1, aid2] = await Promise.all([
client1.identifiers().get(nameMember1),
client2.identifiers().get(nameMember2),
]);

const updates = await Promise.all([
await client1.keyStates().query(aid2.prefix, '1'),
await client1.keyStates().query(aid3.prefix, '0'),
await client2.keyStates().query(aid1.prefix, '1'),
await client2.keyStates().query(aid3.prefix, '0'),
await client3.keyStates().query(aid1.prefix, '1'),
await client3.keyStates().query(aid2.prefix, '1'),
]);

const [aid2State, aid3State, aid1State] = await Promise.all([
waitOperation(client1, updates[0]),
waitOperation(client1, updates[1]),
waitOperation(client2, updates[2]),
waitOperation(client2, updates[3]),
waitOperation(client3, updates[4]),
waitOperation(client3, updates[5]),
]);

const states = [aid1State.response, aid2State.response];
const rstates = [...states, aid3State.response];
const rotateOperation1 = await client1
.identifiers()
.rotate(nameMultisig, { states, rstates });

const serder1 = rotateOperation1.serder;
const sigers = rotateOperation1.sigs.map(
(sig) => new signify.Siger({ qb64: sig })
);
const ims = signify.d(signify.messagize(serder1, sigers));
const atc = ims.substring(serder1.size);
const rembeds = {
rot: [serder1, atc],
};
const smids = states.map((state) => state['i']);
const rmids = rstates.map((state) => state['i']);
const recp = [aid2.state, aid3.state].map((state) => state['i']);

await client1
.exchanges()
.send(
'member1',
'multisig',
aid1,
'/multisig/rot',
{ gid: serder1.pre, smids, rmids },
rembeds,
recp
);

const rotationNotification = await waitAndMarkNotification(
client3,
'/multisig/rot'
);

const response = await client3
.groups()
.getRequest(rotationNotification);
const exn = response[0].exn;

const serder3 = new Serder(exn.e.rot);

const keeper = await client3.manager!.get(aid3);
const sigs = keeper.sign(serder3.raw);

const joinOperation = await client3
.groups()
.join(
nameMultisig,
serder3,
sigs,
exn.a?.gid as string,
smids,
rmids
);

await waitOperation(client3, joinOperation);
});
});

async function createAID(client: SignifyClient, name: string, wits: string[]) {
await getOrCreateIdentifier(client, name, {
wits: wits,
toad: wits.length,
});
return await client.identifiers().get(name);
}

async function waitAndMarkNotification(client: SignifyClient, route: string) {
const notes = await waitForNotifications(client, route);

await Promise.all(
notes.map(async (note) => {
await markNotification(client, note);
})
);

return notes[notes.length - 1]?.a.d ?? '';
}
21 changes: 4 additions & 17 deletions examples/integration-scripts/utils/test-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export async function getOrCreateClients(
);
}
const clients: SignifyClient[] = await Promise.all(tasks);
console.log(`SIGNIFY_SECRETS="${clients.map((i) => i.bran).join(',')}"`);
return clients;
}

Expand All @@ -55,10 +54,6 @@ export async function getOrCreateClient(
if (!res.ok) throw new Error();
await client.connect();
}
console.log('client', {
agent: client.agent?.pre,
controller: client.controller.pre,
});
return client;
}

Expand All @@ -80,7 +75,6 @@ export async function getOrCreateIdentifier(
let id: any = undefined;
try {
const identfier = await client.identifiers().get(name);
// console.log("identifiers.get", identfier);
id = identfier.prefix;
} catch {
const env = resolveEnvironment();
Expand All @@ -93,21 +87,18 @@ export async function getOrCreateIdentifier(
.create(name, kargs);
let op = await result.op();
op = await waitOperation(client, op);
// console.log("identifiers.create", op);
id = op.response.i;
}
const eid = client.agent?.pre!;
if (!(await hasEndRole(client, name, 'agent', eid))) {
const eid = client.agent?.pre;
if (!(await hasEndRole(client, name, 'agent', eid!))) {
const result: EventResult = await client
.identifiers()
.addEndRole(name, 'agent', eid);
let op = await result.op();
op = await waitOperation(client, op);
// console.log("identifiers.addEndRole", op);
const op = await result.op();
await waitOperation(client, op);
}
const oobi = await client.oobis().get(name, 'agent');
const result: [string, string] = [id, oobi.oobis[0]];
console.log(name, result);
return result;
}

Expand All @@ -126,7 +117,6 @@ export async function getEndRoles(
const response: Response = await client.fetch(path, 'GET', null);
if (!response.ok) throw new Error(await response.text());
const result = await response.json();
// console.log("getEndRoles", result);
return result;
}

Expand Down Expand Up @@ -163,16 +153,13 @@ export async function getOrCreateContact(
oobi: string
): Promise<string> {
const list = await client.contacts().list(undefined, 'alias', `^${name}$`);
// console.log("contacts.list", list);
if (list.length > 0) {
const contact = list[0];
if (contact.oobi === oobi) {
// console.log("contacts.id", contact.id);
return contact.id;
}
}
let op = await client.oobis().resolve(oobi, name);
op = await waitOperation(client, op);
// console.log("oobis.resolve", op);
return op.response.i;
}
2 changes: 0 additions & 2 deletions examples/integration-scripts/utils/test-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,10 @@ export async function waitOperation<T = any>(
if (t.done !== true) {
throw new Error(`Operation ${name} not done`);
}
console.log('DONE', name);
return t;
}, options);
let i: Operation | undefined = result;
while (i !== undefined) {
// console.log('DELETE', i.name);
await client.operations().delete(i.name);
i = i.metadata?.depends;
}
Expand Down

0 comments on commit 4b7bd58

Please sign in to comment.