Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

INTERNAL PR js-iden3-auth: VidosResolver #1

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"tsc-alias": "^1.8.8",
"tsconfig-paths": "^3.14.2",
"typechain": "^8.1.1",
"typescript": "^4.3.5"
"typescript": "^4.3.5",
"did-resolver": "4.1.0"
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * as auth from '@lib/auth/auth';
export * as resolver from '@lib/state/resolver';
export { default as VidosResolver } from '@lib/state/vidosResolver';
export * as protocol from '@lib/types-sdk';
export { core } from '@0xpolygonid/js-sdk';
133 changes: 133 additions & 0 deletions src/state/vidosResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/* eslint-disable prettier/prettier */
import { Id } from '@iden3/js-iden3-core';
import { type IStateResolver, type ResolvedState, isGenesisStateId } from './resolver';
import type { DIDDocument, DIDResolutionResult, VerificationMethod } from 'did-resolver';

/**
* Extended DID resolution result that includes additional information about Polygon ID resolution.
*/
type PolygonDidResolutionResult = DIDResolutionResult & {
didDocument: DIDDocument & {
verificationMethod: (VerificationMethod & {
info: {
id: string;
state: string;
replacedByState: string;
createdAtTimestamp: string;
replacedAtTimestamp: string;
createdAtBlock: string;
replacedAtBlock: string;
};
global: {
root: string;
replacedByRoot: string;
createdAtTimestamp: string;
replacedAtTimestamp: string;
createdAtBlock: string;
replacedAtBlock: string;
};
})[];
};
};

/**
* Implementation of {@link IStateResolver} that uses Vidos resolver service to resolve states.
* It can serve as drop-in replacement for EthStateResolver.
*/
export default class VidosResolver implements IStateResolver {
constructor(private readonly resolverUrl: string, private readonly apiKey: string, private readonly network: 'main' | 'mumbai' | 'amoy' = 'main') {}

// Note: implementation closely resembles EthStateResolver because Vidos resolver internally uses the same contract.
// The only difference is the usage of regular HTTP requests instead of web3 calls.

async rootResolve(state: bigint): Promise<ResolvedState> {
const stateHex = state.toString(16);

const zeroAddress = '11111111111111111111'; // 1 is 0 in base58
const did = `did:polygonid:polygon:${this.network}:${zeroAddress}?gist=${stateHex}`;

const response = await fetch(`${this.resolverUrl}/${encodeURIComponent(did)}`, {
method: 'GET',
headers: {
Authorization: `Bearer ${this.apiKey}`
}
});
const result = (await response.json()) as PolygonDidResolutionResult;
if (result.didResolutionMetadata.error) {
throw new Error(`error resolving DID: ${result.didResolutionMetadata.error}`);
}

const globalInfo = result.didDocument.verificationMethod[0].global;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest checking for an error in result.didResolutionMetadata.error before going too far as otherwise likely will give an incorrect result

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 7165914, error is thrown on such resolution error

if (globalInfo == null) throw new Error('gist info not found');

if (globalInfo.root !== stateHex) {
throw new Error('gist info contains invalid state');
}

if (globalInfo.replacedByRoot !== '0') {
if (globalInfo.replacedAtTimestamp === '0') {
throw new Error('state was replaced, but replaced time unknown');
}
return {
latest: false,
state: state,
transitionTimestamp: globalInfo.replacedAtTimestamp,
genesis: false
};
}

return {
latest: true,
state: state,
transitionTimestamp: 0,
genesis: false
};
}

async resolve(id: bigint, state: bigint): Promise<ResolvedState> {
const iden3Id = Id.fromBigInt(id);
const stateHex = state.toString(16);

const did = `did:polygonid:polygon:${this.network}:${iden3Id.string()}`;

const didWithState = `${did}?state=${stateHex}`;
const response = await fetch(`${this.resolverUrl}/${encodeURIComponent(didWithState)}`, {
method: 'GET',
headers: {
Authorization: `Bearer ${this.apiKey}`
}
});
const result = (await response.json()) as PolygonDidResolutionResult;
if (result.didResolutionMetadata.error) {
throw new Error(`error resolving DID: ${result.didResolutionMetadata.error}`);
}

const isGenesis = isGenesisStateId(id, state);

const stateInfo = result.didDocument.verificationMethod[0].info;
if (stateInfo == null) throw new Error('state info not found');

if (stateInfo.id !== did) {
throw new Error(`state was recorded for another identity`);
}

if (stateInfo.state !== stateHex) {
if (stateInfo.replacedAtTimestamp === '0') {
throw new Error(`no information about state transition`);
}
return {
latest: false,
genesis: false,
state: state,
transitionTimestamp: Number.parseInt(stateInfo.replacedAtTimestamp)
};
}

return {
latest: stateInfo.replacedAtTimestamp === '0',
genesis: isGenesis,
state,
transitionTimestamp: Number.parseInt(stateInfo.replacedAtTimestamp)
};
}
}