@beclab/olaresid 0.1.12 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLI-TREE.md +107 -0
- package/CLI.md +122 -1329
- package/README.md +30 -12
- package/SDK-TREE.md +151 -0
- package/TAG.md +95 -41
- package/config.json +6 -4
- package/dist/abi/TerminusDIDQueryABI.d.ts +397 -0
- package/dist/abi/TerminusDIDQueryABI.d.ts.map +1 -0
- package/dist/abi/TerminusDIDQueryABI.js +519 -0
- package/dist/abi/TerminusDIDQueryABI.js.map +1 -0
- package/dist/business/index.d.ts +1 -1
- package/dist/business/index.d.ts.map +1 -1
- package/dist/business/index.js +11 -24
- package/dist/business/index.js.map +1 -1
- package/dist/business/tag-context.d.ts +1 -0
- package/dist/business/tag-context.d.ts.map +1 -1
- package/dist/business/tag-context.js +13 -7
- package/dist/business/tag-context.js.map +1 -1
- package/dist/cli.js +238 -107
- package/dist/cli.js.map +1 -1
- package/dist/config/index.d.ts +16 -4
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +28 -14
- package/dist/config/index.js.map +1 -1
- package/dist/domain/core.d.ts +65 -0
- package/dist/domain/core.d.ts.map +1 -0
- package/dist/domain/core.js +317 -0
- package/dist/domain/core.js.map +1 -0
- package/dist/domain/index.d.ts +104 -57
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +188 -428
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/types.d.ts +56 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +3 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/index.d.ts +81 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +153 -143
- package/dist/index.js.map +1 -1
- package/dist/utils/crypto-utils.d.ts +124 -0
- package/dist/utils/crypto-utils.d.ts.map +1 -1
- package/dist/utils/crypto-utils.js +156 -8
- package/dist/utils/crypto-utils.js.map +1 -1
- package/dist/utils/error-parser.d.ts.map +1 -1
- package/dist/utils/error-parser.js +2 -1
- package/dist/utils/error-parser.js.map +1 -1
- package/dist/utils/event-parser.d.ts +161 -0
- package/dist/utils/event-parser.d.ts.map +1 -0
- package/dist/utils/event-parser.js +140 -0
- package/dist/utils/event-parser.js.map +1 -0
- package/dist/utils/tag-type-builder.d.ts +43 -0
- package/dist/utils/tag-type-builder.d.ts.map +1 -1
- package/dist/utils/tag-type-builder.js +122 -0
- package/dist/utils/tag-type-builder.js.map +1 -1
- package/dist/utils/tag-type-parser.d.ts +70 -0
- package/dist/utils/tag-type-parser.d.ts.map +1 -0
- package/dist/utils/tag-type-parser.js +190 -0
- package/dist/utils/tag-type-parser.js.map +1 -0
- package/examples/create-with-rpc-demo.ts +142 -0
- package/examples/fetch-all-flat-demo.ts +159 -0
- package/examples/fetch-by-indices-demo.ts +235 -0
- package/examples/fetch-domain-demo.ts +137 -0
- package/examples/fetch-domains-demo.ts +221 -0
- package/examples/frontend-demo/index.html +2 -2
- package/examples/frontend-demo/package-lock.json +4 -1
- package/examples/index.ts +3 -5
- package/jest.config.js +25 -0
- package/package.json +6 -2
- package/src/abi/TerminusDIDQueryABI.ts +516 -0
- package/src/business/index.ts +10 -33
- package/src/business/tag-context.ts +35 -7
- package/src/cli.ts +344 -121
- package/src/config/index.ts +34 -19
- package/src/domain/core.ts +382 -0
- package/src/domain/index.ts +271 -641
- package/src/domain/types.ts +59 -0
- package/src/index.ts +222 -207
- package/src/utils/crypto-utils.ts +239 -2
- package/src/utils/error-parser.ts +2 -1
- package/src/utils/event-parser.ts +353 -0
- package/src/utils/tag-type-builder.ts +138 -0
- package/src/utils/tag-type-parser.ts +246 -0
- package/tests/unit/crypto-utils.test.ts +338 -0
- package/tests/unit/ed25519-jwk.test.ts +201 -0
- package/tests/unit/event-parser.test.ts +690 -0
- package/tests/unit/generate-mnemonic.test.ts +268 -0
- package/tests/unit/olares-id-format.test.ts +321 -0
- package/tests/unit/tag-type-parser.test.ts +802 -0
- package/tests/unit/tag-types.test.ts +821 -0
- package/tsconfig.json +3 -2
- package/dist/abi/ABITypeABI.d.ts +0 -88
- package/dist/abi/ABITypeABI.d.ts.map +0 -1
- package/dist/abi/ABITypeABI.js +0 -382
- package/dist/abi/ABITypeABI.js.map +0 -1
- package/dist/abi/RegistryABI.d.ts +0 -77
- package/dist/abi/RegistryABI.d.ts.map +0 -1
- package/dist/abi/RegistryABI.js +0 -462
- package/dist/abi/RegistryABI.js.map +0 -1
- package/dist/tag/address.d.ts +0 -11
- package/dist/tag/address.d.ts.map +0 -1
- package/dist/tag/address.js +0 -44
- package/dist/tag/address.js.map +0 -1
- package/dist/tag/array.d.ts +0 -14
- package/dist/tag/array.d.ts.map +0 -1
- package/dist/tag/array.js +0 -72
- package/dist/tag/array.js.map +0 -1
- package/dist/tag/bool.d.ts +0 -11
- package/dist/tag/bool.d.ts.map +0 -1
- package/dist/tag/bool.js +0 -43
- package/dist/tag/bool.js.map +0 -1
- package/dist/tag/bytes.d.ts +0 -11
- package/dist/tag/bytes.d.ts.map +0 -1
- package/dist/tag/bytes.js +0 -37
- package/dist/tag/bytes.js.map +0 -1
- package/dist/tag/flarray.d.ts +0 -15
- package/dist/tag/flarray.d.ts.map +0 -1
- package/dist/tag/flarray.js +0 -81
- package/dist/tag/flarray.js.map +0 -1
- package/dist/tag/flbytes.d.ts +0 -11
- package/dist/tag/flbytes.d.ts.map +0 -1
- package/dist/tag/flbytes.js +0 -47
- package/dist/tag/flbytes.js.map +0 -1
- package/dist/tag/index.d.ts +0 -32
- package/dist/tag/index.d.ts.map +0 -1
- package/dist/tag/index.js +0 -121
- package/dist/tag/index.js.map +0 -1
- package/dist/tag/int.d.ts +0 -12
- package/dist/tag/int.d.ts.map +0 -1
- package/dist/tag/int.js +0 -49
- package/dist/tag/int.js.map +0 -1
- package/dist/tag/string.d.ts +0 -11
- package/dist/tag/string.d.ts.map +0 -1
- package/dist/tag/string.js +0 -37
- package/dist/tag/string.js.map +0 -1
- package/dist/tag/tag.d.ts +0 -67
- package/dist/tag/tag.d.ts.map +0 -1
- package/dist/tag/tag.js +0 -157
- package/dist/tag/tag.js.map +0 -1
- package/dist/tag/tuple.d.ts +0 -17
- package/dist/tag/tuple.d.ts.map +0 -1
- package/dist/tag/tuple.js +0 -162
- package/dist/tag/tuple.js.map +0 -1
- package/dist/tag/uint.d.ts +0 -12
- package/dist/tag/uint.d.ts.map +0 -1
- package/dist/tag/uint.js +0 -49
- package/dist/tag/uint.js.map +0 -1
- package/dist/test/did.d.ts +0 -2
- package/dist/test/did.d.ts.map +0 -1
- package/dist/test/did.js +0 -177
- package/dist/test/did.js.map +0 -1
- package/dist/utils/tag-abi-codec.d.ts +0 -69
- package/dist/utils/tag-abi-codec.d.ts.map +0 -1
- package/dist/utils/tag-abi-codec.js +0 -144
- package/dist/utils/tag-abi-codec.js.map +0 -1
- package/examples/crypto-utilities.ts +0 -140
- package/examples/ed25519-jwk.ts +0 -73
- package/examples/generate-mnemonic.ts +0 -149
- package/examples/legacy.ts +0 -33
- package/examples/olares-id-format.ts +0 -197
- package/examples/tag-builder.ts +0 -235
- package/examples/tag-nested-tuple.ts +0 -190
- package/examples/tag-simple.ts +0 -149
- package/examples/tag-tagger.ts +0 -217
- package/examples/test-nested-tuple-conversion.ts +0 -143
- package/examples/test-type-bytes-parser.ts +0 -70
- package/src/abi/ABITypeABI.ts +0 -379
- package/src/abi/RegistryABI.ts +0 -459
- package/src/tag/address.ts +0 -48
- package/src/tag/array.ts +0 -80
- package/src/tag/bool.ts +0 -43
- package/src/tag/bytes.ts +0 -38
- package/src/tag/flarray.ts +0 -99
- package/src/tag/flbytes.ts +0 -48
- package/src/tag/index.ts +0 -170
- package/src/tag/int.ts +0 -51
- package/src/tag/string.ts +0 -38
- package/src/tag/tag.ts +0 -229
- package/src/tag/tuple.ts +0 -193
- package/src/tag/uint.ts +0 -51
- package/src/test/did.ts +0 -346
- package/src/utils/tag-abi-codec.ts +0 -158
|
@@ -82,7 +82,7 @@ async function loadWalletCore(): Promise<any> {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
// multicodec code for Ed25519 keys (0xed)
|
|
85
|
-
const ED25519_CODEC_ID = varint.encode(parseInt('0xed', 16));
|
|
85
|
+
export const ED25519_CODEC_ID = varint.encode(parseInt('0xed', 16));
|
|
86
86
|
|
|
87
87
|
// ============================================================================
|
|
88
88
|
// Mnemonic and Key Derivation Functions
|
|
@@ -149,6 +149,40 @@ export async function getEthereumAddressFromMnemonic(
|
|
|
149
149
|
return wallet.getAddressForCoin(CoinType.ethereum);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Derive Ethereum address from private key
|
|
154
|
+
* Uses ethers.Wallet to get the address from private key
|
|
155
|
+
*
|
|
156
|
+
* @param privateKey EVM private key in hex format (with or without 0x prefix)
|
|
157
|
+
* @returns Ethereum address (0x...)
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const address = getEthereumAddressFromPrivateKey('0x1234...');
|
|
162
|
+
* console.log(address); // "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export function getEthereumAddressFromPrivateKey(privateKey: string): string {
|
|
166
|
+
// Import ethers dynamically to match the pattern in index.ts
|
|
167
|
+
const { ethers } = require('ethers');
|
|
168
|
+
|
|
169
|
+
// Ensure privateKey has 0x prefix
|
|
170
|
+
const normalizedKey = privateKey.startsWith('0x')
|
|
171
|
+
? privateKey
|
|
172
|
+
: `0x${privateKey}`;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const wallet = new ethers.Wallet(normalizedKey);
|
|
176
|
+
return wallet.address;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Invalid private key: ${
|
|
180
|
+
error instanceof Error ? error.message : String(error)
|
|
181
|
+
}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
152
186
|
/**
|
|
153
187
|
* Derive EVM-compatible private key from mnemonic using Trust Wallet Core
|
|
154
188
|
* Uses standard BIP44 derivation path for Ethereum (m/44'/60'/0'/0/0)
|
|
@@ -300,6 +334,7 @@ export async function getEd25519JwkFromMnemonic(mnemonic: string): Promise<{
|
|
|
300
334
|
idBytes.set(publicKeyBytes, ED25519_CODEC_ID.length);
|
|
301
335
|
const id = base58btc.encode(idBytes);
|
|
302
336
|
const did = `did:key:${id}`;
|
|
337
|
+
const kid = `${did}#${id}`; // Fully-qualified verification method ID
|
|
303
338
|
|
|
304
339
|
// Base64url encode the keys
|
|
305
340
|
const x = base64url.baseEncode(publicKeyBytes);
|
|
@@ -311,7 +346,7 @@ export async function getEd25519JwkFromMnemonic(mnemonic: string): Promise<{
|
|
|
311
346
|
crv: 'Ed25519', // Curve: Ed25519
|
|
312
347
|
alg: 'EdDSA', // Algorithm: EdDSA
|
|
313
348
|
use: 'sig', // Use: signature
|
|
314
|
-
kid:
|
|
349
|
+
kid: kid, // Fully-qualified verification method ID (did:key:z...#z...)
|
|
315
350
|
x: x // Public key parameter
|
|
316
351
|
};
|
|
317
352
|
|
|
@@ -513,3 +548,205 @@ export function createRsaKeyPair(
|
|
|
513
548
|
return generateKeyPairBrowser(length);
|
|
514
549
|
}
|
|
515
550
|
}
|
|
551
|
+
|
|
552
|
+
// ============================================================================
|
|
553
|
+
// DID Type Definitions (from @bytetrade/core)
|
|
554
|
+
// ============================================================================
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Jwk base type - identifies the cryptographic algorithm family used with the key.
|
|
558
|
+
*/
|
|
559
|
+
interface Jwk {
|
|
560
|
+
/** The "alg" (algorithm) parameter identifies the algorithm intended for use with the key. */
|
|
561
|
+
alg?: string;
|
|
562
|
+
/** The "kid" (key ID) parameter identifies the key. */
|
|
563
|
+
kid?: string;
|
|
564
|
+
/** identifies the cryptographic algorithm family used with the key, such "EC" or "OKP". */
|
|
565
|
+
kty: string;
|
|
566
|
+
/** The "use" (public key use) parameter identifies the intended use of the public key. */
|
|
567
|
+
use?: string;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* PublicJwk represents a public key in JWK format.
|
|
572
|
+
*/
|
|
573
|
+
export interface PublicJwk extends Jwk {
|
|
574
|
+
/** The "crv" (curve) parameter identifies the cryptographic curve used with the key. */
|
|
575
|
+
crv: string;
|
|
576
|
+
/** The x coordinate for the Elliptic Curve point, base64url encoded. */
|
|
577
|
+
x: string;
|
|
578
|
+
/** The y coordinate for the Elliptic Curve point, base64url encoded. Optional for Ed25519. */
|
|
579
|
+
y?: string;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* PrivateJwk represents a private key in JWK format.
|
|
584
|
+
*/
|
|
585
|
+
export interface PrivateJwk extends PublicJwk {
|
|
586
|
+
/** The private key value, base64url encoded. */
|
|
587
|
+
d: string;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Linked Data Key Types - identifies the type of verification method.
|
|
592
|
+
*/
|
|
593
|
+
export enum LDKeyType {
|
|
594
|
+
X25519KeyAgreementKey2020 = 'X25519KeyAgreementKey2020',
|
|
595
|
+
Ed25519VerificationKey2020 = 'Ed25519VerificationKey2020',
|
|
596
|
+
X25519KeyAgreementKey2019 = 'X25519KeyAgreementKey2019',
|
|
597
|
+
Ed25519VerificationKey2018 = 'Ed25519VerificationKey2018',
|
|
598
|
+
EcdsaSecp256k1VerificationKey2019 = 'EcdsaSecp256k1VerificationKey2019'
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* VerificationMethod represents a verification method in a DID document.
|
|
603
|
+
*/
|
|
604
|
+
export interface VerificationMethod {
|
|
605
|
+
id: string;
|
|
606
|
+
type: LDKeyType | string;
|
|
607
|
+
controller: string;
|
|
608
|
+
publicKeyBase58?: string;
|
|
609
|
+
publicKeyJwk?: PublicJwk;
|
|
610
|
+
publicKeyMultibase?: string;
|
|
611
|
+
blockchainAccountId?: string;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* DIDDocument represents a W3C DID Document.
|
|
616
|
+
*/
|
|
617
|
+
export interface DIDDocument {
|
|
618
|
+
'@context'?: any;
|
|
619
|
+
id?: string;
|
|
620
|
+
controller?: string;
|
|
621
|
+
alsoKnownAs?: string;
|
|
622
|
+
verificationMethod?: VerificationMethod[];
|
|
623
|
+
authentication?: (string | VerificationMethod)[];
|
|
624
|
+
assertionMethod?: (string | VerificationMethod)[];
|
|
625
|
+
keyAgreement?: (string | VerificationMethod)[];
|
|
626
|
+
capabilityInvocation?: (string | VerificationMethod)[];
|
|
627
|
+
capabilityDelegation?: (string | VerificationMethod)[];
|
|
628
|
+
services?: Service[];
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Service endpoint in a DID document.
|
|
633
|
+
*/
|
|
634
|
+
export interface Service {
|
|
635
|
+
id: string;
|
|
636
|
+
type: string;
|
|
637
|
+
serviceEndpoint: any;
|
|
638
|
+
routingKeys?: string[];
|
|
639
|
+
accept?: string[];
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// ============================================================================
|
|
643
|
+
// DID / JWK Utilities
|
|
644
|
+
// ============================================================================
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Build a fully-qualified verification method ID from a DID.
|
|
648
|
+
* e.g. "did:key:z6Mk..." → "did:key:z6Mk...#z6Mk..."
|
|
649
|
+
*/
|
|
650
|
+
export function getFullyQualifiedVerificationMethodID(did: string): string {
|
|
651
|
+
const base = did.split('#')[0];
|
|
652
|
+
const [, , id] = base.split(':');
|
|
653
|
+
return `${base}#${id}`;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Construct a PublicJwk from a DID and an already-decoded base64url `x` value.
|
|
658
|
+
*/
|
|
659
|
+
export function getPublicJWKFromX(did: string, x: string): PublicJwk {
|
|
660
|
+
return {
|
|
661
|
+
alg: 'EdDSA',
|
|
662
|
+
crv: 'Ed25519',
|
|
663
|
+
kid: did,
|
|
664
|
+
kty: 'OKP',
|
|
665
|
+
use: 'sig',
|
|
666
|
+
x
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Derive a PublicJwk directly from a did:key string.
|
|
672
|
+
*/
|
|
673
|
+
export function getPublicJWKFromDID(did: string): PublicJwk {
|
|
674
|
+
const base = did.split('#')[0];
|
|
675
|
+
const [scheme, method, id] = base.split(':');
|
|
676
|
+
if (scheme !== 'did')
|
|
677
|
+
throw new Error('Malformed DID: scheme must be "did"');
|
|
678
|
+
if (method !== 'key')
|
|
679
|
+
throw new Error('Unsupported DID method: must be "key"');
|
|
680
|
+
|
|
681
|
+
const idBytes = base58btc.decode(id);
|
|
682
|
+
const x = base64url.baseEncode(idBytes.slice(ED25519_CODEC_ID.length));
|
|
683
|
+
return getPublicJWKFromX(base, x);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Construct a PrivateJwk from a DID and a base64url-encoded private key `d`.
|
|
688
|
+
*/
|
|
689
|
+
export function getPrivateJWKFromD(did: string, d: string): PrivateJwk {
|
|
690
|
+
return { ...getPublicJWKFromDID(did), d };
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Encode a raw Ed25519 public key (Uint8Array) to a multicodec base58btc id string.
|
|
695
|
+
*/
|
|
696
|
+
export function getIDFromEd25519Pubkey(publicKey: Uint8Array): string {
|
|
697
|
+
const idBytes = new Uint8Array(publicKey.length + ED25519_CODEC_ID.length);
|
|
698
|
+
idBytes.set(ED25519_CODEC_ID, 0);
|
|
699
|
+
idBytes.set(publicKey, ED25519_CODEC_ID.length);
|
|
700
|
+
return base58btc.encode(idBytes);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Construct a PrivateJwk from raw Ed25519 public/private key bytes.
|
|
705
|
+
*/
|
|
706
|
+
export function getPrivateJWKFromEd25519(
|
|
707
|
+
publicKey: Uint8Array,
|
|
708
|
+
privateKey: Uint8Array
|
|
709
|
+
): PrivateJwk {
|
|
710
|
+
const id = getIDFromEd25519Pubkey(publicKey);
|
|
711
|
+
const keyId = `did:key:${id}#${id}`;
|
|
712
|
+
return {
|
|
713
|
+
alg: 'EdDSA',
|
|
714
|
+
crv: 'Ed25519',
|
|
715
|
+
kid: keyId,
|
|
716
|
+
kty: 'OKP',
|
|
717
|
+
use: 'sig',
|
|
718
|
+
x: base64url.baseEncode(publicKey),
|
|
719
|
+
d: base64url.baseEncode(privateKey)
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Resolve a did:key DID into a W3C DIDDocument.
|
|
725
|
+
*/
|
|
726
|
+
export function resolveDID(did: string): DIDDocument {
|
|
727
|
+
const publicJwk = getPublicJWKFromDID(did);
|
|
728
|
+
const base = did.split('#')[0];
|
|
729
|
+
const [, , id] = base.split(':');
|
|
730
|
+
const methodId = `#${id}`;
|
|
731
|
+
|
|
732
|
+
return {
|
|
733
|
+
'@context': [
|
|
734
|
+
'https://www.w3.org/ns/did/v1',
|
|
735
|
+
'https://w3id.org/security/suites/ed25519-2020/v1',
|
|
736
|
+
'https://w3id.org/security/suites/x25519-2020/v1'
|
|
737
|
+
],
|
|
738
|
+
id: base,
|
|
739
|
+
verificationMethod: [
|
|
740
|
+
{
|
|
741
|
+
id: methodId,
|
|
742
|
+
type: LDKeyType.Ed25519VerificationKey2020,
|
|
743
|
+
controller: base,
|
|
744
|
+
publicKeyJwk: publicJwk
|
|
745
|
+
}
|
|
746
|
+
],
|
|
747
|
+
authentication: [methodId],
|
|
748
|
+
assertionMethod: [methodId],
|
|
749
|
+
capabilityDelegation: [methodId],
|
|
750
|
+
capabilityInvocation: [methodId]
|
|
751
|
+
};
|
|
752
|
+
}
|
|
@@ -108,7 +108,8 @@ export function parseContractError(error: any): ParsedContractError {
|
|
|
108
108
|
const errorSelector = error.data.slice(0, 10);
|
|
109
109
|
errorName = ERROR_SELECTORS[errorSelector];
|
|
110
110
|
} catch (e) {
|
|
111
|
-
|
|
111
|
+
console.error('[error-parser] failed to parse error selector', e);
|
|
112
|
+
throw e;
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import DID_ABI from '../abi/TerminusDIDABI';
|
|
3
|
+
|
|
4
|
+
// ============================================================
|
|
5
|
+
// Raw Log Type (from eth_getLogs RPC response)
|
|
6
|
+
// ============================================================
|
|
7
|
+
|
|
8
|
+
export interface EthLog {
|
|
9
|
+
address: string;
|
|
10
|
+
topics: string[];
|
|
11
|
+
data: string;
|
|
12
|
+
blockNumber: string; // hex string
|
|
13
|
+
transactionHash: string;
|
|
14
|
+
transactionIndex: string; // hex string
|
|
15
|
+
blockHash: string;
|
|
16
|
+
logIndex: string; // hex string
|
|
17
|
+
removed: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ============================================================
|
|
21
|
+
// Event Args Types
|
|
22
|
+
// ============================================================
|
|
23
|
+
|
|
24
|
+
/** Transfer (ERC721) — from=0x0 means mint */
|
|
25
|
+
export interface TransferArgs {
|
|
26
|
+
from: string;
|
|
27
|
+
to: string;
|
|
28
|
+
tokenId: bigint;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Approval (ERC721) */
|
|
32
|
+
export interface ApprovalArgs {
|
|
33
|
+
owner: string;
|
|
34
|
+
approved: string;
|
|
35
|
+
tokenId: bigint;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** ApprovalForAll (ERC721) */
|
|
39
|
+
export interface ApprovalForAllArgs {
|
|
40
|
+
owner: string;
|
|
41
|
+
operator: string;
|
|
42
|
+
approved: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Initialized — emitted on proxy initialization */
|
|
46
|
+
export interface InitializedArgs {
|
|
47
|
+
version: bigint;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** NewTagType — emitted when a tag type is defined via defineTag() */
|
|
51
|
+
export interface NewTagTypeArgs {
|
|
52
|
+
domain: string;
|
|
53
|
+
name: string;
|
|
54
|
+
abiType: string; // bytes, hex string
|
|
55
|
+
fieldNamesHash: string[]; // bytes32[]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** OffchainStringArray — emitted to log string[] values off-chain */
|
|
59
|
+
export interface OffchainStringArrayArgs {
|
|
60
|
+
hash: string; // bytes32, indexed
|
|
61
|
+
value: string[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** OwnershipTransferStarted */
|
|
65
|
+
export interface OwnershipTransferStartedArgs {
|
|
66
|
+
previousOwner: string;
|
|
67
|
+
newOwner: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** OwnershipTransferred */
|
|
71
|
+
export interface OwnershipTransferredArgs {
|
|
72
|
+
previousOwner: string;
|
|
73
|
+
newOwner: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** TagAdded — emitted when a tag value is set on a domain */
|
|
77
|
+
export interface TagAddedArgs {
|
|
78
|
+
from: string; // domain that owns the tag definition
|
|
79
|
+
to: string; // domain being tagged
|
|
80
|
+
name: string;
|
|
81
|
+
value: string; // bytes, hex string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** TagElemPopped — array element removed from a tag */
|
|
85
|
+
export interface TagElemPoppedArgs {
|
|
86
|
+
from: string;
|
|
87
|
+
to: string;
|
|
88
|
+
name: string;
|
|
89
|
+
elemPath: bigint[]; // uint256[]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** TagElemPushed — array element appended to a tag */
|
|
93
|
+
export interface TagElemPushedArgs {
|
|
94
|
+
from: string;
|
|
95
|
+
to: string;
|
|
96
|
+
name: string;
|
|
97
|
+
elemPath: bigint[]; // uint256[]
|
|
98
|
+
value: string; // bytes, hex string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** TagElemUpdated — array element updated in a tag */
|
|
102
|
+
export interface TagElemUpdatedArgs {
|
|
103
|
+
from: string;
|
|
104
|
+
to: string;
|
|
105
|
+
name: string;
|
|
106
|
+
elemPath: bigint[]; // uint256[]
|
|
107
|
+
value: string; // bytes, hex string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** TagRemoved — tag value removed from a domain */
|
|
111
|
+
export interface TagRemovedArgs {
|
|
112
|
+
from: string;
|
|
113
|
+
to: string;
|
|
114
|
+
name: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** TransferByParentOwner — subdomain transferred by parent domain owner */
|
|
118
|
+
export interface TransferByParentOwnerArgs {
|
|
119
|
+
tokenId: bigint;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** TransferBySuperAdmin — domain transferred by super admin */
|
|
123
|
+
export interface TransferBySuperAdminArgs {
|
|
124
|
+
tokenId: bigint;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Upgraded — UUPS proxy upgraded to new implementation */
|
|
128
|
+
export interface UpgradedArgs {
|
|
129
|
+
implementation: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ============================================================
|
|
133
|
+
// Event Name Union & Args Map
|
|
134
|
+
// ============================================================
|
|
135
|
+
|
|
136
|
+
export type TerminusDIDEventName =
|
|
137
|
+
| 'Transfer'
|
|
138
|
+
| 'Approval'
|
|
139
|
+
| 'ApprovalForAll'
|
|
140
|
+
| 'Initialized'
|
|
141
|
+
| 'NewTagType'
|
|
142
|
+
| 'OffchainStringArray'
|
|
143
|
+
| 'OwnershipTransferStarted'
|
|
144
|
+
| 'OwnershipTransferred'
|
|
145
|
+
| 'TagAdded'
|
|
146
|
+
| 'TagElemPopped'
|
|
147
|
+
| 'TagElemPushed'
|
|
148
|
+
| 'TagElemUpdated'
|
|
149
|
+
| 'TagRemoved'
|
|
150
|
+
| 'TransferByParentOwner'
|
|
151
|
+
| 'TransferBySuperAdmin'
|
|
152
|
+
| 'Upgraded';
|
|
153
|
+
|
|
154
|
+
export interface TerminusDIDEventArgsMap {
|
|
155
|
+
Transfer: TransferArgs;
|
|
156
|
+
Approval: ApprovalArgs;
|
|
157
|
+
ApprovalForAll: ApprovalForAllArgs;
|
|
158
|
+
Initialized: InitializedArgs;
|
|
159
|
+
NewTagType: NewTagTypeArgs;
|
|
160
|
+
OffchainStringArray: OffchainStringArrayArgs;
|
|
161
|
+
OwnershipTransferStarted: OwnershipTransferStartedArgs;
|
|
162
|
+
OwnershipTransferred: OwnershipTransferredArgs;
|
|
163
|
+
TagAdded: TagAddedArgs;
|
|
164
|
+
TagElemPopped: TagElemPoppedArgs;
|
|
165
|
+
TagElemPushed: TagElemPushedArgs;
|
|
166
|
+
TagElemUpdated: TagElemUpdatedArgs;
|
|
167
|
+
TagRemoved: TagRemovedArgs;
|
|
168
|
+
TransferByParentOwner: TransferByParentOwnerArgs;
|
|
169
|
+
TransferBySuperAdmin: TransferBySuperAdminArgs;
|
|
170
|
+
Upgraded: UpgradedArgs;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ============================================================
|
|
174
|
+
// Parsed Event Types
|
|
175
|
+
// ============================================================
|
|
176
|
+
|
|
177
|
+
export interface ParsedEvent<T extends TerminusDIDEventName> {
|
|
178
|
+
eventName: T;
|
|
179
|
+
blockNumber: number;
|
|
180
|
+
transactionHash: string;
|
|
181
|
+
logIndex: number;
|
|
182
|
+
tokenId: bigint | undefined;
|
|
183
|
+
args: TerminusDIDEventArgsMap[T];
|
|
184
|
+
raw: EthLog;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export type AnyParsedEvent = {
|
|
188
|
+
[K in TerminusDIDEventName]: ParsedEvent<K>;
|
|
189
|
+
}[TerminusDIDEventName];
|
|
190
|
+
|
|
191
|
+
// ============================================================
|
|
192
|
+
// Type Guards
|
|
193
|
+
// ============================================================
|
|
194
|
+
|
|
195
|
+
export function isTransferEvent(
|
|
196
|
+
event: AnyParsedEvent
|
|
197
|
+
): event is ParsedEvent<'Transfer'> {
|
|
198
|
+
return event.eventName === 'Transfer';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function isMintEvent(
|
|
202
|
+
event: AnyParsedEvent
|
|
203
|
+
): event is ParsedEvent<'Transfer'> {
|
|
204
|
+
return (
|
|
205
|
+
event.eventName === 'Transfer' &&
|
|
206
|
+
event.args.from === '0x0000000000000000000000000000000000000000'
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function isTagAddedEvent(
|
|
211
|
+
event: AnyParsedEvent
|
|
212
|
+
): event is ParsedEvent<'TagAdded'> {
|
|
213
|
+
return event.eventName === 'TagAdded';
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function isTagRemovedEvent(
|
|
217
|
+
event: AnyParsedEvent
|
|
218
|
+
): event is ParsedEvent<'TagRemoved'> {
|
|
219
|
+
return event.eventName === 'TagRemoved';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function isTagElemUpdatedEvent(
|
|
223
|
+
event: AnyParsedEvent
|
|
224
|
+
): event is ParsedEvent<'TagElemUpdated'> {
|
|
225
|
+
return event.eventName === 'TagElemUpdated';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function isTagElemPushedEvent(
|
|
229
|
+
event: AnyParsedEvent
|
|
230
|
+
): event is ParsedEvent<'TagElemPushed'> {
|
|
231
|
+
return event.eventName === 'TagElemPushed';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function isTagElemPoppedEvent(
|
|
235
|
+
event: AnyParsedEvent
|
|
236
|
+
): event is ParsedEvent<'TagElemPopped'> {
|
|
237
|
+
return event.eventName === 'TagElemPopped';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function isNewTagTypeEvent(
|
|
241
|
+
event: AnyParsedEvent
|
|
242
|
+
): event is ParsedEvent<'NewTagType'> {
|
|
243
|
+
return event.eventName === 'NewTagType';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ============================================================
|
|
247
|
+
// Parser
|
|
248
|
+
// ============================================================
|
|
249
|
+
|
|
250
|
+
const _iface = new ethers.Interface(DID_ABI.abi);
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Derive tokenId from a domain name, matching the on-chain formula:
|
|
254
|
+
* uint256(keccak256(bytes(domain)))
|
|
255
|
+
*/
|
|
256
|
+
function domainToTokenId(domain: string): bigint {
|
|
257
|
+
return BigInt(ethers.keccak256(ethers.toUtf8Bytes(domain)));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Extract tokenId from event args.
|
|
262
|
+
*
|
|
263
|
+
* ✅ directly in args: Transfer, TransferByParentOwner, TransferBySuperAdmin
|
|
264
|
+
* ✅ derived locally: NewTagType (args.domain), Tag* events (args.to)
|
|
265
|
+
* ❌ not applicable: Approval, ApprovalForAll, Initialized, Upgraded,
|
|
266
|
+
* OwnershipTransferred*, OffchainStringArray
|
|
267
|
+
*/
|
|
268
|
+
function extractTokenId(
|
|
269
|
+
eventName: TerminusDIDEventName,
|
|
270
|
+
args: Record<string, unknown>
|
|
271
|
+
): bigint | undefined {
|
|
272
|
+
switch (eventName) {
|
|
273
|
+
case 'Transfer':
|
|
274
|
+
case 'TransferByParentOwner':
|
|
275
|
+
case 'TransferBySuperAdmin':
|
|
276
|
+
return args['tokenId'] as bigint;
|
|
277
|
+
case 'NewTagType':
|
|
278
|
+
return domainToTokenId(args['domain'] as string);
|
|
279
|
+
case 'TagAdded':
|
|
280
|
+
case 'TagRemoved':
|
|
281
|
+
case 'TagElemUpdated':
|
|
282
|
+
case 'TagElemPushed':
|
|
283
|
+
case 'TagElemPopped':
|
|
284
|
+
return domainToTokenId(args['to'] as string);
|
|
285
|
+
default:
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Parse raw eth_getLogs entries using the TerminusDID contract ABI.
|
|
292
|
+
*
|
|
293
|
+
* Logs that don't match any known event (e.g. from a different contract)
|
|
294
|
+
* are silently skipped.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* const logs = await provider.getLogs({ address: CONTRACT_ADDRESS, fromBlock, toBlock });
|
|
299
|
+
* const events = parseEvents(logs);
|
|
300
|
+
* for (const event of events) {
|
|
301
|
+
* if (isTransferEvent(event)) {
|
|
302
|
+
* console.log('Transfer:', event.args.from, '->', event.args.to, event.args.tokenId);
|
|
303
|
+
* }
|
|
304
|
+
* }
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
export function parseEvents(logs: EthLog[]): AnyParsedEvent[] {
|
|
308
|
+
const result: AnyParsedEvent[] = [];
|
|
309
|
+
|
|
310
|
+
for (const log of logs) {
|
|
311
|
+
try {
|
|
312
|
+
const parsed = _iface.parseLog({
|
|
313
|
+
topics: log.topics,
|
|
314
|
+
data: log.data
|
|
315
|
+
});
|
|
316
|
+
if (!parsed) {
|
|
317
|
+
console.warn(
|
|
318
|
+
'[event-parser] parseLog returned null, matching event cannot be found',
|
|
319
|
+
{
|
|
320
|
+
tx: log.transactionHash,
|
|
321
|
+
logIndex: log.logIndex
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const args: Record<string, unknown> = {};
|
|
328
|
+
parsed.fragment.inputs.forEach((input, idx) => {
|
|
329
|
+
args[input.name] = parsed.args[idx];
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const eventName = parsed.name as TerminusDIDEventName;
|
|
333
|
+
result.push({
|
|
334
|
+
eventName,
|
|
335
|
+
blockNumber: parseInt(log.blockNumber, 16),
|
|
336
|
+
transactionHash: log.transactionHash,
|
|
337
|
+
logIndex: parseInt(log.logIndex, 16),
|
|
338
|
+
tokenId: extractTokenId(eventName, args),
|
|
339
|
+
args: args as unknown as TerminusDIDEventArgsMap[TerminusDIDEventName],
|
|
340
|
+
raw: log
|
|
341
|
+
} as AnyParsedEvent);
|
|
342
|
+
} catch (err) {
|
|
343
|
+
console.error('[event-parser] failed to parse log', {
|
|
344
|
+
tx: log.transactionHash,
|
|
345
|
+
logIndex: log.logIndex,
|
|
346
|
+
err
|
|
347
|
+
});
|
|
348
|
+
throw err;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return result;
|
|
353
|
+
}
|