Skip to content

Commit

Permalink
fix: provide a way to pass the anchor and issuance events when creati…
Browse files Browse the repository at this point in the history
…ng credential
  • Loading branch information
lenkan committed Oct 16, 2024
1 parent 5801e63 commit 25215bf
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 70 deletions.
12 changes: 6 additions & 6 deletions examples/integration-scripts/multisig-holder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,23 +460,23 @@ async function createRegistry(
async function issueCredential(
client: SignifyClient,
name: string,
data: CredentialData
acdc: CredentialData
) {
const result = await client.credentials().issue(name, data);
const result = await client.credentials().issue(name, { acdc });

await waitOperation(client, result.op);

const creds = await client.credentials().list();
assert.equal(creds.length, 1);
assert.equal(creds[0].sad.s, data.s);
assert.equal(creds[0].sad.s, acdc.s);
assert.equal(creds[0].status.s, '0');

const dt = createTimestamp();

if (data.a.i) {
if (acdc.a.i) {
const [grant, gsigs, end] = await client.ipex().grant({
senderName: name,
recipient: data.a.i,
recipient: acdc.a.i,
datetime: dt,
acdc: result.acdc,
anc: result.anc,
Expand All @@ -485,7 +485,7 @@ async function issueCredential(

let op = await client
.ipex()
.submitGrant(name, grant, gsigs, end, [data.a.i]);
.submitGrant(name, grant, gsigs, end, [acdc.a.i]);
op = await waitOperation(client, op);
}

Expand Down
20 changes: 10 additions & 10 deletions examples/integration-scripts/multisig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import {
assertOperations,
getOrCreateClient,
getOrCreateIdentifier,
markNotification,
waitAndMarkNotification,
waitForNotifications,
waitOperation,
warnNotifications,
} from './utils/test-util';
Expand Down Expand Up @@ -882,12 +880,14 @@ test('multisig', async function run() {

const TIME = new Date().toISOString().replace('Z', '000+00:00');
const credRes = await client1.credentials().issue('multisig', {
ri: regk,
s: SCHEMA_SAID,
a: {
i: holder,
dt: TIME,
...vcdata,
acdc: {
ri: regk,
s: SCHEMA_SAID,
a: {
i: holder,
dt: TIME,
...vcdata,
},
},
});
op1 = credRes.op;
Expand All @@ -906,7 +906,7 @@ test('multisig', async function run() {
exn = res[0].exn;

const credentialSaid = exn.e.acdc.d;
const credRes2 = await client2.credentials().issue('multisig', exn.e.acdc);
const credRes2 = await client2.credentials().issue('multisig', exn.e);

op2 = credRes2.op;
await multisigIssue(client2, 'member2', 'multisig', credRes2);
Expand All @@ -920,7 +920,7 @@ test('multisig', async function run() {
res = await client3.groups().getRequest(msgSaid);
exn = res[0].exn;

const credRes3 = await client3.credentials().issue('multisig', exn.e.acdc);
const credRes3 = await client3.credentials().issue('multisig', exn.e);

op3 = credRes3.op;
await multisigIssue(client3, 'member3', 'multisig', credRes3);
Expand Down
18 changes: 10 additions & 8 deletions examples/integration-scripts/utils/test-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,16 +318,18 @@ export async function getOrIssueCredential(
}

const issResult = await issuerClient.credentials().issue(issuerAid.name, {
ri: issuerRegistry.regk,
s: schema,
u: privacy ? new Salter({}).qb64 : undefined,
a: {
i: recipientAid.prefix,
acdc: {
ri: issuerRegistry.regk,
s: schema,
u: privacy ? new Salter({}).qb64 : undefined,
...credData,
a: {
i: recipientAid.prefix,
u: privacy ? new Salter({}).qb64 : undefined,
...credData,
},
r: rules,
e: source,
},
r: rules,
e: source,
});

await waitOperation(issuerClient, issResult.op);
Expand Down
120 changes: 77 additions & 43 deletions src/keri/app/credentialing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from '../core/utils';
import { Operation } from './coring';
import { HabState } from '../core/state';
import { CesrNumber } from '../core/number';

/** Types of credentials */
export class CredentialTypes {
Expand Down Expand Up @@ -85,6 +86,29 @@ export interface CredentialData {
r?: { [key: string]: unknown };
}

export interface IssueCredentialArgs {
/**
* The credential data.
*/
acdc: CredentialData;

/**
* The issuance event to be anchored to the credential registry. If not provided, the issuance event will be derived
* from the credential data.
*
* If a credential is created as part of a multisig exchanged, the anchoring event can be found in the exchange message.
*/
iss?: Record<string, unknown>;

/**
* The anchoring event for the credential issuance. If not provided, the anchor event will be calculated from
* from the credential data and the issuance event.
*
* If a credential is created as part of a multisig exchanged, the anchoring event can be found in the exchange message.
*/
anc?: Record<string, unknown>;
}

export interface IssueCredentialResult {
acdc: Serder;
anc: Serder;
Expand Down Expand Up @@ -290,7 +314,7 @@ export class Credentials {
*/
async issue(
name: string,
args: CredentialData
args: IssueCredentialArgs
): Promise<IssueCredentialResult> {
const hab = await this.client.identifiers().get(name);
const estOnly = hab.state.c !== undefined && hab.state.c.includes('EO');
Expand All @@ -306,55 +330,65 @@ export class Credentials {

const [, subject] = Saider.saidify({
d: '',
...args.a,
dt: args.a.dt ?? new Date().toISOString().replace('Z', '000+00:00'),
...args.acdc.a,
dt:
args.acdc.a.dt ??
new Date().toISOString().replace('Z', '000+00:00'),
});

const [, acdc] = Saider.saidify({
v: versify(Ident.ACDC, undefined, Serials.JSON, 0),
d: '',
u: args.u,
i: args.i ?? hab.prefix,
ri: args.ri,
s: args.s,
a: subject,
e: args.e,
r: args.r,
});
const acdc = new Serder(
Saider.saidify({
v: versify(Ident.ACDC, undefined, Serials.JSON, 0),
d: '',
u: args.acdc.u,
i: args.acdc.i ?? hab.prefix,
ri: args.acdc.ri,
s: args.acdc.s,
a: subject,
e: args.acdc.e,
r: args.acdc.r,
})[1]
);

const [, iss] = Saider.saidify({
v: versify(Ident.KERI, undefined, Serials.JSON, 0),
t: Ilks.iss,
d: '',
i: acdc.d,
s: '0',
ri: args.ri,
dt: subject.dt,
});
const iss = new Serder(
args.iss ??
Saider.saidify({
v: versify(Ident.KERI, undefined, Serials.JSON, 0),
t: Ilks.iss,
d: '',
i: acdc.ked.d,
s: '0',
ri: args.acdc.ri,
dt: subject.dt,
})[1]
);

const sn = parseInt(hab.state.s, 16);
const anc = interact({
pre: hab.prefix,
sn: sn + 1,
data: [
{
i: iss.i,
s: iss.s,
d: iss.d,
},
],
dig: hab.state.d,
version: undefined,
kind: undefined,
});
const sn = new CesrNumber({}, parseInt(hab.state.s, 16) + 1);
const anc = new Serder(
args.anc ??
Saider.saidify({
v: versify(Ident.KERI, undefined, Serials.JSON, 0),
t: Ilks.ixn,
d: '',
i: hab.prefix,
s: sn.numh,
p: hab.state.d,
a: [
{
i: iss.ked.i,
s: iss.ked.s,
d: iss.ked.d,
},
],
})[1]
);

const sigs = await keeper.sign(b(anc.raw));

const path = `/identifiers/${hab.name}/credentials`;
const method = 'POST';
const body = {
acdc: acdc,
iss: iss,
acdc: acdc.ked,
iss: iss.ked,
ixn: anc.ked,
sigs,
[keeper.algo]: keeper.params(),
Expand All @@ -368,8 +402,8 @@ export class Credentials {
const op = await res.json();

return {
acdc: new Serder(acdc),
iss: new Serder(iss),
acdc,
iss,
anc,
op,
};
Expand Down
8 changes: 5 additions & 3 deletions test/app/credentialing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,11 @@ describe('Credentialing', () => {
const schema = 'EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao';
const isuee = 'EG2XjQN-3jPN5rcR4spLjaJyM4zA6Lgg-Hd5vSMymu5p';
await credentials.issue('aid1', {
ri: registry,
s: schema,
a: { i: isuee, LEI: '1234' },
acdc: {
ri: registry,
s: schema,
a: { i: isuee, LEI: '1234' },
},
});
lastCall = fetchMock.mock.calls[fetchMock.mock.calls.length - 1]!;
lastBody = JSON.parse(lastCall[1]!.body!.toString());
Expand Down

0 comments on commit 25215bf

Please sign in to comment.