@beclab/olaresid 0.1.1 → 0.1.3

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.
Files changed (93) hide show
  1. package/CLI.md +1300 -0
  2. package/README.md +40 -31
  3. package/TAG.md +589 -0
  4. package/dist/abi/RootResolver2ABI.d.ts +54 -0
  5. package/dist/abi/RootResolver2ABI.d.ts.map +1 -0
  6. package/dist/abi/RootResolver2ABI.js +240 -0
  7. package/dist/abi/RootResolver2ABI.js.map +1 -0
  8. package/dist/business/index.d.ts +302 -0
  9. package/dist/business/index.d.ts.map +1 -0
  10. package/dist/business/index.js +1211 -0
  11. package/dist/business/index.js.map +1 -0
  12. package/dist/business/tag-context.d.ts +219 -0
  13. package/dist/business/tag-context.d.ts.map +1 -0
  14. package/dist/business/tag-context.js +560 -0
  15. package/dist/business/tag-context.js.map +1 -0
  16. package/dist/cli.js +2102 -39
  17. package/dist/cli.js.map +1 -1
  18. package/dist/debug.d.ts.map +1 -1
  19. package/dist/debug.js +14 -2
  20. package/dist/debug.js.map +1 -1
  21. package/dist/index.d.ts +51 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +241 -12
  24. package/dist/index.js.map +1 -1
  25. package/dist/utils/crypto-utils.d.ts +130 -0
  26. package/dist/utils/crypto-utils.d.ts.map +1 -0
  27. package/dist/utils/crypto-utils.js +402 -0
  28. package/dist/utils/crypto-utils.js.map +1 -0
  29. package/dist/utils/error-parser.d.ts +35 -0
  30. package/dist/utils/error-parser.d.ts.map +1 -0
  31. package/dist/utils/error-parser.js +202 -0
  32. package/dist/utils/error-parser.js.map +1 -0
  33. package/dist/utils/olares-id.d.ts +36 -0
  34. package/dist/utils/olares-id.d.ts.map +1 -0
  35. package/dist/utils/olares-id.js +52 -0
  36. package/dist/utils/olares-id.js.map +1 -0
  37. package/dist/utils/tag-abi-codec.d.ts +69 -0
  38. package/dist/utils/tag-abi-codec.d.ts.map +1 -0
  39. package/dist/utils/tag-abi-codec.js +144 -0
  40. package/dist/utils/tag-abi-codec.js.map +1 -0
  41. package/dist/utils/tag-type-builder.d.ts +158 -0
  42. package/dist/utils/tag-type-builder.d.ts.map +1 -0
  43. package/dist/utils/tag-type-builder.js +410 -0
  44. package/dist/utils/tag-type-builder.js.map +1 -0
  45. package/examples/crypto-utilities.ts +140 -0
  46. package/examples/domain-context.ts +80 -0
  47. package/examples/generate-mnemonic.ts +149 -0
  48. package/examples/index.ts +1 -1
  49. package/examples/ip.ts +171 -0
  50. package/examples/legacy.ts +10 -10
  51. package/examples/list-wallets.ts +81 -0
  52. package/examples/olares-id-format.ts +197 -0
  53. package/examples/quasar-demo/.eslintrc.js +23 -0
  54. package/examples/quasar-demo/.quasar/app.js +43 -0
  55. package/examples/quasar-demo/.quasar/client-entry.js +38 -0
  56. package/examples/quasar-demo/.quasar/client-prefetch.js +130 -0
  57. package/examples/quasar-demo/.quasar/quasar-user-options.js +16 -0
  58. package/examples/quasar-demo/README.md +49 -0
  59. package/examples/quasar-demo/index.html +11 -0
  60. package/examples/quasar-demo/package-lock.json +6407 -0
  61. package/examples/quasar-demo/package.json +36 -0
  62. package/examples/quasar-demo/quasar.config.js +73 -0
  63. package/examples/quasar-demo/src/App.vue +13 -0
  64. package/examples/quasar-demo/src/css/app.scss +1 -0
  65. package/examples/quasar-demo/src/layouts/MainLayout.vue +21 -0
  66. package/examples/quasar-demo/src/pages/IndexPage.vue +905 -0
  67. package/examples/quasar-demo/src/router/index.ts +25 -0
  68. package/examples/quasar-demo/src/router/routes.ts +11 -0
  69. package/examples/quasar-demo/tsconfig.json +28 -0
  70. package/examples/register-subdomain.ts +152 -0
  71. package/examples/rsa-keypair.ts +148 -0
  72. package/examples/tag-builder.ts +235 -0
  73. package/examples/tag-management.ts +534 -0
  74. package/examples/tag-nested-tuple.ts +190 -0
  75. package/examples/tag-simple.ts +149 -0
  76. package/examples/tag-tagger.ts +217 -0
  77. package/examples/test-nested-tuple-conversion.ts +143 -0
  78. package/examples/test-type-bytes-parser.ts +70 -0
  79. package/examples/transfer-domain.ts +197 -0
  80. package/examples/wallet-management.ts +196 -0
  81. package/package.json +24 -15
  82. package/src/abi/RootResolver2ABI.ts +237 -0
  83. package/src/business/index.ts +1492 -0
  84. package/src/business/tag-context.ts +747 -0
  85. package/src/cli.ts +2772 -39
  86. package/src/debug.ts +17 -2
  87. package/src/index.ts +313 -17
  88. package/src/utils/crypto-utils.ts +459 -0
  89. package/src/utils/error-parser.ts +225 -0
  90. package/src/utils/olares-id.ts +49 -0
  91. package/src/utils/tag-abi-codec.ts +158 -0
  92. package/src/utils/tag-type-builder.ts +469 -0
  93. package/tsconfig.json +1 -1
@@ -0,0 +1,25 @@
1
+ import { route } from 'quasar/wrappers';
2
+ import {
3
+ createMemoryHistory,
4
+ createRouter,
5
+ createWebHashHistory,
6
+ createWebHistory
7
+ } from 'vue-router';
8
+
9
+ import routes from './routes';
10
+
11
+ export default route(function (/* { store, ssrContext } */) {
12
+ const createHistory = process.env.SERVER
13
+ ? createMemoryHistory
14
+ : process.env.VUE_ROUTER_MODE === 'history'
15
+ ? createWebHistory
16
+ : createWebHashHistory;
17
+
18
+ const Router = createRouter({
19
+ scrollBehavior: () => ({ left: 0, top: 0 }),
20
+ routes,
21
+ history: createHistory(process.env.VUE_ROUTER_BASE)
22
+ });
23
+
24
+ return Router;
25
+ });
@@ -0,0 +1,11 @@
1
+ import { RouteRecordRaw } from 'vue-router';
2
+
3
+ const routes: RouteRecordRaw[] = [
4
+ {
5
+ path: '/',
6
+ component: () => import('layouts/MainLayout.vue'),
7
+ children: [{ path: '', component: () => import('pages/IndexPage.vue') }]
8
+ }
9
+ ];
10
+
11
+ export default routes;
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2019",
4
+ "module": "ES2020",
5
+ "moduleResolution": "node",
6
+ "lib": ["ES2019", "DOM", "DOM.Iterable"],
7
+ "jsx": "preserve",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "baseUrl": ".",
15
+ "paths": {
16
+ "src/*": ["src/*"],
17
+ "app/*": ["*"],
18
+ "components/*": ["src/components/*"],
19
+ "layouts/*": ["src/layouts/*"],
20
+ "pages/*": ["src/pages/*"],
21
+ "assets/*": ["src/assets/*"],
22
+ "boot/*": ["src/boot/*"]
23
+ },
24
+ "types": ["node"]
25
+ },
26
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
27
+ "exclude": ["node_modules"]
28
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Example: Register a subdomain using mnemonic-derived keys
3
+ *
4
+ * This example demonstrates how to:
5
+ * 1. Connect to the network with a wallet
6
+ * 2. Initialize OlaresID
7
+ * 3. Generate a mnemonic for the subdomain
8
+ * 4. Register the subdomain
9
+ */
10
+
11
+ import OlaresID, { generateMnemonic } from '../src/index';
12
+
13
+ async function main() {
14
+ console.log('🔐 Subdomain Registration Example\n');
15
+ console.log('='.repeat(60));
16
+
17
+ // ============================================================================
18
+ // Step 1: Setup
19
+ // ============================================================================
20
+ console.log('\n📝 Step 1: Setup Network and Wallet');
21
+ console.log('-'.repeat(60));
22
+
23
+ // Check for required environment variables
24
+ if (!process.env.PRIVATE_KEY_OR_MNEMONIC) {
25
+ console.error(
26
+ '❌ Error: PRIVATE_KEY_OR_MNEMONIC environment variable is required'
27
+ );
28
+ console.log('\nUsage:');
29
+ console.log(' export PRIVATE_KEY_OR_MNEMONIC=0x... (private key)');
30
+ console.log(' # Or');
31
+ console.log(
32
+ ' export PRIVATE_KEY_OR_MNEMONIC="your twelve words..." (mnemonic)'
33
+ );
34
+ console.log(' npx ts-node examples/register-subdomain-example.ts\n');
35
+ process.exit(1);
36
+ }
37
+
38
+ // ============================================================================
39
+ // Step 2: Initialize OlaresID
40
+ // ============================================================================
41
+ console.log('\n📝 Step 2: Initialize OlaresID');
42
+ console.log('-'.repeat(60));
43
+
44
+ const olaresId = OlaresID.createTestnet();
45
+ await olaresId.setSigner(process.env.PRIVATE_KEY_OR_MNEMONIC);
46
+
47
+ console.log('✅ OlaresID initialized for OP Sepolia Testnet');
48
+
49
+ // ============================================================================
50
+ // Step 3: Get Parent Domain
51
+ // ============================================================================
52
+ console.log('\n📝 Step 3: Get Parent Domain Information');
53
+ console.log('-'.repeat(60));
54
+
55
+ // Replace with your actual parent domain
56
+ const PARENT_DOMAIN = process.env.PARENT_DOMAIN || 'tw7613781.olares.com';
57
+ const parentDomain = olaresId.domain(PARENT_DOMAIN);
58
+
59
+ console.log(`📋 Parent domain: ${PARENT_DOMAIN}`);
60
+
61
+ try {
62
+ const parentInfo = await parentDomain.getMetaInfo();
63
+ console.log('✅ Parent domain found:');
64
+ console.log(` - ID: ${parentInfo.id}`);
65
+ console.log(` - DID: ${parentInfo.did}`);
66
+ console.log(` - Note: ${parentInfo.note}`);
67
+ console.log(` - Allow Subdomain: ${parentInfo.allowSubdomain}`);
68
+ } catch (error: any) {
69
+ console.error(
70
+ `❌ Error: Parent domain "${PARENT_DOMAIN}" not found or not accessible`
71
+ );
72
+ console.error(` ${error.message}`);
73
+ process.exit(1);
74
+ }
75
+
76
+ // ============================================================================
77
+ // Step 4: Generate Mnemonic for Subdomain
78
+ // ============================================================================
79
+ console.log('\n📝 Step 4: Generate Mnemonic for Subdomain');
80
+ console.log('-'.repeat(60));
81
+
82
+ const mnemonic = generateMnemonic(12);
83
+ console.log('✅ Generated 12-word mnemonic:');
84
+ console.log(` ${mnemonic}`);
85
+ console.log(
86
+ '\n⚠️ IMPORTANT: Save this mnemonic securely! It controls the subdomain.'
87
+ );
88
+
89
+ // ============================================================================
90
+ // Step 5: Register Subdomain
91
+ // ============================================================================
92
+ console.log('\n📝 Step 5: Register Subdomain');
93
+ console.log('-'.repeat(60));
94
+
95
+ const SUBDOMAIN_LABEL = process.env.SUBDOMAIN || 'example-child';
96
+ console.log(`📋 Subdomain label: ${SUBDOMAIN_LABEL}`);
97
+ console.log(`📋 Full domain will be: ${SUBDOMAIN_LABEL}.${PARENT_DOMAIN}`);
98
+
99
+ console.log('\n⏳ Submitting transaction...');
100
+
101
+ try {
102
+ const result = await parentDomain.registerSubdomain(
103
+ SUBDOMAIN_LABEL,
104
+ mnemonic
105
+ );
106
+
107
+ if (result.success) {
108
+ console.log('\n✅ Subdomain registered successfully!\n');
109
+ console.log('='.repeat(60));
110
+ console.log('Registration Details:');
111
+ console.log('='.repeat(60));
112
+ console.log(`Subdomain label: ${result.data.subdomain}`);
113
+ console.log(`Full domain name: ${result.data.fullDomainName}`);
114
+ console.log(`Owner address: ${result.data.owner}`);
115
+ console.log(`DID: ${result.data.did}`);
116
+ console.log(`Transaction hash: ${result.transactionHash}`);
117
+ console.log(
118
+ `Gas used: ${result.gasUsed?.toString() || 'N/A'}`
119
+ );
120
+ console.log(`Block number: ${result.blockNumber || 'N/A'}`);
121
+ console.log('='.repeat(60));
122
+
123
+ console.log('\n🔗 View on block explorer:');
124
+ console.log(
125
+ ` https://sepolia-optimism.etherscan.io/tx/${result.transactionHash}`
126
+ );
127
+ } else {
128
+ console.error('\n❌ Subdomain registration failed!');
129
+ console.error(` Error: ${result.error}`);
130
+ process.exit(1);
131
+ }
132
+ } catch (error: any) {
133
+ console.error('\n❌ Unexpected error during registration:');
134
+ console.error(` ${error.message}`);
135
+ if (error.stack) {
136
+ console.error('\nStack trace:');
137
+ console.error(error.stack);
138
+ }
139
+ process.exit(1);
140
+ }
141
+
142
+ // ============================================================================
143
+ // Done
144
+ // ============================================================================
145
+ console.log('\n✅ Example completed successfully!\n');
146
+ }
147
+
148
+ // Run the example
149
+ main().catch((error) => {
150
+ console.error('Fatal error:', error);
151
+ process.exit(1);
152
+ });
@@ -0,0 +1,148 @@
1
+ import OlaresID, { createRsaKeyPair, pemToDer, derToPem } from '../src/index';
2
+
3
+ async function main() {
4
+ console.log('='.repeat(60));
5
+ console.log('Testing RSA Key Pair Generation and Conversion');
6
+ console.log('='.repeat(60));
7
+
8
+ // Test 1: Create RSA key pair
9
+ console.log('\n🔑 Test 1: createRsaKeyPair()');
10
+ console.log('-'.repeat(60));
11
+ try {
12
+ const keyPair = await createRsaKeyPair();
13
+ console.log('✅ Successfully generated RSA key pair');
14
+ console.log('\n📄 Public Key (PEM):');
15
+ console.log(keyPair.rsaPublicKey);
16
+ console.log('\n📄 Private Key (PEM):');
17
+ console.log(keyPair.rsaPrivateKey);
18
+
19
+ // Test 2: Convert PEM to DER
20
+ console.log('\n🔄 Test 2: pemToDer()');
21
+ console.log('-'.repeat(60));
22
+ const derHex = pemToDer(keyPair.rsaPublicKey);
23
+ console.log('✅ Successfully converted PEM to DER hex');
24
+ console.log('DER Hex:');
25
+ console.log(derHex);
26
+
27
+ // Test 2.5: Convert DER back to PEM
28
+ console.log('\n🔄 Test 2.5: derToPem()');
29
+ console.log('-'.repeat(60));
30
+ const pemFromDer = derToPem(derHex);
31
+ console.log('✅ Successfully converted DER hex back to PEM');
32
+ console.log(pemFromDer);
33
+
34
+ // Verify round-trip conversion
35
+ const originalPemNormalized = keyPair.rsaPublicKey
36
+ .replace(/\s/g, '')
37
+ .replace(/-----BEGIN.*?-----/g, '')
38
+ .replace(/-----END.*?-----/g, '');
39
+ const convertedPemNormalized = pemFromDer
40
+ .replace(/\s/g, '')
41
+ .replace(/-----BEGIN.*?-----/g, '')
42
+ .replace(/-----END.*?-----/g, '');
43
+
44
+ if (originalPemNormalized === convertedPemNormalized) {
45
+ console.log('✅ Round-trip conversion successful!');
46
+ } else {
47
+ console.log('⚠️ Round-trip conversion mismatch');
48
+ }
49
+
50
+ // Test 3: Set RSA public key using PEM format
51
+ if (process.env.PRIVATE_KEY_OR_MNEMONIC) {
52
+ console.log('\n📝 Test 3: setRSAPublicKey() with PEM format');
53
+ console.log('-'.repeat(60));
54
+
55
+ const didConsole = OlaresID.createTestnet();
56
+ await didConsole.setSigner(process.env.PRIVATE_KEY_OR_MNEMONIC);
57
+
58
+ const testDomain = '1.com';
59
+ const domain = didConsole.domain(testDomain);
60
+
61
+ // Set using PEM format (will be automatically converted to DER)
62
+ const result = await domain.setRSAPublicKey(keyPair.rsaPublicKey);
63
+
64
+ if (result.success) {
65
+ console.log('✅ Success:');
66
+ console.log(' Transaction Hash:', result.transactionHash);
67
+ console.log(' Gas Used:', result.gasUsed?.toString());
68
+
69
+ // Wait for the blockchain to index the data
70
+ console.log('⏳ Waiting for blockchain to index data...');
71
+ await new Promise((resolve) => setTimeout(resolve, 5000));
72
+ } else {
73
+ console.log('❌ Failed:', result.error);
74
+ }
75
+
76
+ // Verify the key was set
77
+ console.log('\n🔍 Test 4: Verify RSA public key');
78
+ console.log('-'.repeat(60));
79
+ const storedKey = await domain.getRSAPublicKey();
80
+ if (storedKey) {
81
+ console.log('✅ RSA Public Key found on chain (PEM format):');
82
+ console.log(storedKey);
83
+
84
+ // Compare with our original key
85
+ const originalNormalized = keyPair.rsaPublicKey
86
+ .replace(/\s/g, '')
87
+ .replace(/-----BEGIN.*?-----/g, '')
88
+ .replace(/-----END.*?-----/g, '');
89
+ const storedNormalized = storedKey
90
+ .replace(/\s/g, '')
91
+ .replace(/-----BEGIN.*?-----/g, '')
92
+ .replace(/-----END.*?-----/g, '');
93
+
94
+ if (storedNormalized === originalNormalized) {
95
+ console.log('✅ Stored key matches our original PEM key!');
96
+ } else {
97
+ console.log('⚠️ Stored key differs from original');
98
+ }
99
+ } else {
100
+ console.log('❌ No RSA Public Key found');
101
+ }
102
+
103
+ // Test 5: Remove RSA public key
104
+ console.log('\n🗑️ Test 5: removeRSAPublicKey()');
105
+ console.log('-'.repeat(60));
106
+ const removeResult = await domain.removeRSAPublicKey();
107
+
108
+ if (removeResult.success) {
109
+ console.log('✅ Success:');
110
+ console.log(
111
+ ' Transaction Hash:',
112
+ removeResult.transactionHash
113
+ );
114
+ console.log(' Gas Used:', removeResult.gasUsed?.toString());
115
+
116
+ // Wait for the blockchain to index the data
117
+ console.log('⏳ Waiting for blockchain to index data...');
118
+ await new Promise((resolve) => setTimeout(resolve, 5000));
119
+ } else {
120
+ console.log('❌ Failed:', removeResult.error);
121
+ }
122
+
123
+ // Test 6: Verify the key was removed
124
+ console.log('\n🔍 Test 6: Verify RSA public key after removal');
125
+ console.log('-'.repeat(60));
126
+ const removedKey = await domain.getRSAPublicKey();
127
+ if (removedKey) {
128
+ console.log('❌ RSA Public Key still exists:', removedKey);
129
+ } else {
130
+ console.log('✅ RSA Public Key successfully removed');
131
+ }
132
+
133
+ didConsole.clearSigner();
134
+ } else {
135
+ console.log(
136
+ '\n⚠️ Skipping blockchain tests (no PRIVATE_KEY_OR_MNEMONIC provided)'
137
+ );
138
+ }
139
+ } catch (error) {
140
+ console.error('❌ Failed:', error);
141
+ }
142
+
143
+ console.log('\n' + '='.repeat(60));
144
+ console.log('✅ All tests completed!');
145
+ console.log('='.repeat(60));
146
+ }
147
+
148
+ main().catch(console.error);
@@ -0,0 +1,235 @@
1
+ /**
2
+ * TagTypeBuilder Example
3
+ *
4
+ * This example demonstrates how to use TagTypeBuilder to:
5
+ * - Create various Tag types offline (no contract calls)
6
+ * - See the generated ABI type bytes
7
+ * - Understand the encoding rules
8
+ *
9
+ * This is purely informational - no blockchain interaction required.
10
+ *
11
+ * Run:
12
+ * npx ts-node examples/tag-builder.ts
13
+ */
14
+
15
+ import { TagTypeBuilder } from '../src/index';
16
+
17
+ console.log('\n' + '='.repeat(70));
18
+ console.log('TagTypeBuilder - Offline ABI Type Encoding Demo');
19
+ console.log('='.repeat(70) + '\n');
20
+
21
+ // ========================================
22
+ // 1. Basic Types
23
+ // ========================================
24
+ console.log('📦 Part 1: Basic Types');
25
+ console.log('-'.repeat(70));
26
+
27
+ const stringType = TagTypeBuilder.string();
28
+ console.log(`string → 0x${stringType.getTypeBytes()}`);
29
+
30
+ const addressType = TagTypeBuilder.address();
31
+ console.log(`address → 0x${addressType.getTypeBytes()}`);
32
+
33
+ const boolType = TagTypeBuilder.bool();
34
+ console.log(`bool → 0x${boolType.getTypeBytes()}`);
35
+
36
+ const uint8Type = TagTypeBuilder.uint8();
37
+ console.log(`uint8 → 0x${uint8Type.getTypeBytes()}`);
38
+
39
+ const uint256Type = TagTypeBuilder.uint256();
40
+ console.log(`uint256 → 0x${uint256Type.getTypeBytes()}`);
41
+
42
+ const bytes32Type = TagTypeBuilder.bytes32();
43
+ console.log(`bytes32 → 0x${bytes32Type.getTypeBytes()}`);
44
+
45
+ const bytesType = TagTypeBuilder.bytes();
46
+ console.log(`bytes → 0x${bytesType.getTypeBytes()}`);
47
+
48
+ console.log();
49
+
50
+ // ========================================
51
+ // 2. Array Types
52
+ // ========================================
53
+ console.log('📦 Part 2: Array Types (Dynamic)');
54
+ console.log('-'.repeat(70));
55
+
56
+ const addressArrayType = TagTypeBuilder.addressArray();
57
+ console.log(`address[] → 0x${addressArrayType.getTypeBytes()}`);
58
+ console.log(` = 0x04 (array) + 0x07 (address)`);
59
+
60
+ const stringArrayType = TagTypeBuilder.stringArray();
61
+ console.log(`string[] → 0x${stringArrayType.getTypeBytes()}`);
62
+ console.log(` = 0x04 (array) + 0x03 (string)`);
63
+
64
+ const uint256ArrayType = TagTypeBuilder.uint256Array();
65
+ console.log(`uint256[] → 0x${uint256ArrayType.getTypeBytes()}`);
66
+ console.log(` = 0x04 (array) + 0x0120 (uint256)`);
67
+
68
+ // Nested array
69
+ const nestedArrayType = TagTypeBuilder.array(TagTypeBuilder.addressArray());
70
+ console.log(`address[][] → 0x${nestedArrayType.getTypeBytes()}`);
71
+ console.log(` = 0x04 (array) + 0x0407 (address[])`);
72
+
73
+ console.log();
74
+
75
+ // ========================================
76
+ // 3. Fixed-Length Array Types
77
+ // ========================================
78
+ console.log('📦 Part 3: Fixed-Length Arrays');
79
+ console.log('-'.repeat(70));
80
+
81
+ const fixedArray5 = TagTypeBuilder.fixedArray(TagTypeBuilder.address(), 5);
82
+ console.log(`address[5] → 0x${fixedArray5.getTypeBytes()}`);
83
+ console.log(
84
+ ` = 0x05 (fixed array) + 0x0005 (length 5) + 0x07 (address)`
85
+ );
86
+
87
+ const fixedArray10 = TagTypeBuilder.fixedArray(TagTypeBuilder.uint8(), 10);
88
+ console.log(`uint8[10] → 0x${fixedArray10.getTypeBytes()}`);
89
+ console.log(
90
+ ` = 0x05 (fixed array) + 0x000A (length 10) + 0x0101 (uint8)`
91
+ );
92
+
93
+ console.log();
94
+
95
+ // ========================================
96
+ // 4. Tuple Types (Struct)
97
+ // ========================================
98
+ console.log('📦 Part 4: Tuple Types (Struct)');
99
+ console.log('-'.repeat(70));
100
+
101
+ // Simple tuple
102
+ const userType = TagTypeBuilder.tuple({
103
+ name: TagTypeBuilder.string(),
104
+ age: TagTypeBuilder.uint8()
105
+ });
106
+ console.log(`tuple(string name, uint8 age)`);
107
+ console.log(` → 0x${userType.getTypeBytes()}`);
108
+ console.log(
109
+ ` = 0x06 (tuple) + 0x0002 (2 fields) + 0x03 (string) + 0x0101 (uint8)`
110
+ );
111
+ console.log(` Field names: ${JSON.stringify(userType.getFieldNames())}`);
112
+
113
+ console.log();
114
+
115
+ // Complex tuple
116
+ const profileType = TagTypeBuilder.tuple({
117
+ username: TagTypeBuilder.string(),
118
+ age: TagTypeBuilder.uint8(),
119
+ wallets: TagTypeBuilder.addressArray(),
120
+ verified: TagTypeBuilder.bool()
121
+ });
122
+ console.log(
123
+ `tuple(string username, uint8 age, address[] wallets, bool verified)`
124
+ );
125
+ console.log(` → 0x${profileType.getTypeBytes()}`);
126
+ console.log(` = 0x06 (tuple)`);
127
+ console.log(` + 0x0004 (4 fields)`);
128
+ console.log(` + 0x03 (string)`);
129
+ console.log(` + 0x0101 (uint8)`);
130
+ console.log(` + 0x0407 (address[])`);
131
+ console.log(` + 0x02 (bool)`);
132
+ console.log(` Field names: ${JSON.stringify(profileType.getFieldNames())}`);
133
+
134
+ console.log();
135
+
136
+ // ========================================
137
+ // 5. Nested Tuple Types
138
+ // ========================================
139
+ console.log('📦 Part 5: Nested Tuple Types');
140
+ console.log('-'.repeat(70));
141
+
142
+ const addressBookType = TagTypeBuilder.tuple({
143
+ owner: TagTypeBuilder.tuple({
144
+ name: TagTypeBuilder.string(),
145
+ wallet: TagTypeBuilder.address()
146
+ }),
147
+ contacts: TagTypeBuilder.array(
148
+ TagTypeBuilder.tuple({
149
+ name: TagTypeBuilder.string(),
150
+ wallet: TagTypeBuilder.address()
151
+ })
152
+ )
153
+ });
154
+
155
+ console.log(`Complex nested tuple:`);
156
+ console.log(` → 0x${addressBookType.getTypeBytes()}`);
157
+ console.log(
158
+ ` Field names: ${JSON.stringify(
159
+ addressBookType.getFieldNames(),
160
+ null,
161
+ 2
162
+ )}`
163
+ );
164
+
165
+ console.log();
166
+
167
+ // ========================================
168
+ // 6. Array of Tuples
169
+ // ========================================
170
+ console.log('📦 Part 6: Array of Tuples');
171
+ console.log('-'.repeat(70));
172
+
173
+ const authAddressType = TagTypeBuilder.array(
174
+ TagTypeBuilder.tuple({
175
+ algorithm: TagTypeBuilder.uint8(),
176
+ addr: TagTypeBuilder.address()
177
+ })
178
+ );
179
+
180
+ console.log(`tuple(uint8 algorithm, address addr)[]`);
181
+ console.log(` → 0x${authAddressType.getTypeBytes()}`);
182
+ console.log(` = 0x04 (array)`);
183
+ console.log(` + 0x06 (tuple)`);
184
+ console.log(` + 0x0002 (2 fields)`);
185
+ console.log(` + 0x0101 (uint8)`);
186
+ console.log(` + 0x07 (address)`);
187
+ console.log(
188
+ ` Field names: ${JSON.stringify(authAddressType.getFieldNames())}`
189
+ );
190
+
191
+ console.log();
192
+
193
+ // ========================================
194
+ // 7. Encoding Rules Summary
195
+ // ========================================
196
+ console.log('📦 Part 7: Encoding Rules Summary');
197
+ console.log('-'.repeat(70));
198
+ console.log(`
199
+ Type Code | Type | Encoding
200
+ --------- | ----------- | ----------------------------------------
201
+ 0x00 | int | 0x00 + size (size = bits / 8)
202
+ 0x01 | uint | 0x01 + size (size = bits / 8)
203
+ 0x02 | bool | 0x02
204
+ 0x03 | string | 0x03
205
+ 0x04 | array | 0x04 + elementType
206
+ 0x05 | fixedArray | 0x05 + length (2 bytes) + elementType
207
+ 0x06 | tuple | 0x06 + fieldCount (2 bytes) + fieldTypes...
208
+ 0x07 | address | 0x07
209
+ 0x08 | fixedBytes | 0x08 + size (1-32)
210
+ 0x09 | bytes | 0x09
211
+
212
+ Examples:
213
+ uint8 = 0x0101 (0x01 for uint + 0x01 for 8 bits / 8)
214
+ uint256 = 0x0120 (0x01 for uint + 0x20 for 256 bits / 8 = 32)
215
+ bytes32 = 0x0820 (0x08 for fixed bytes + 0x20 for 32 bytes)
216
+
217
+ Array Examples:
218
+ address[] = 0x0407 (0x04 + 0x07)
219
+ address[][] = 0x040407 (0x04 + 0x0407)
220
+ address[5] = 0x05000507 (0x05 + 0x0005 + 0x07)
221
+
222
+ Tuple Examples:
223
+ tuple(string, uint8) = 0x06000203 0101
224
+ ^^ ^^^^ ^^ ^^^^
225
+ | | | uint8
226
+ | | string
227
+ | 2 fields
228
+ tuple
229
+ `);
230
+
231
+ console.log('='.repeat(70));
232
+ console.log('✅ TagTypeBuilder Demo Completed');
233
+ console.log('='.repeat(70) + '\n');
234
+ console.log('💡 Key Takeaway: All ABI type bytes are calculated OFFLINE!');
235
+ console.log(' No blockchain calls needed for type definition.\n');