@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.
- package/CLI.md +1300 -0
- package/README.md +40 -31
- package/TAG.md +589 -0
- package/dist/abi/RootResolver2ABI.d.ts +54 -0
- package/dist/abi/RootResolver2ABI.d.ts.map +1 -0
- package/dist/abi/RootResolver2ABI.js +240 -0
- package/dist/abi/RootResolver2ABI.js.map +1 -0
- package/dist/business/index.d.ts +302 -0
- package/dist/business/index.d.ts.map +1 -0
- package/dist/business/index.js +1211 -0
- package/dist/business/index.js.map +1 -0
- package/dist/business/tag-context.d.ts +219 -0
- package/dist/business/tag-context.d.ts.map +1 -0
- package/dist/business/tag-context.js +560 -0
- package/dist/business/tag-context.js.map +1 -0
- package/dist/cli.js +2102 -39
- package/dist/cli.js.map +1 -1
- package/dist/debug.d.ts.map +1 -1
- package/dist/debug.js +14 -2
- package/dist/debug.js.map +1 -1
- package/dist/index.d.ts +51 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +241 -12
- package/dist/index.js.map +1 -1
- package/dist/utils/crypto-utils.d.ts +130 -0
- package/dist/utils/crypto-utils.d.ts.map +1 -0
- package/dist/utils/crypto-utils.js +402 -0
- package/dist/utils/crypto-utils.js.map +1 -0
- package/dist/utils/error-parser.d.ts +35 -0
- package/dist/utils/error-parser.d.ts.map +1 -0
- package/dist/utils/error-parser.js +202 -0
- package/dist/utils/error-parser.js.map +1 -0
- package/dist/utils/olares-id.d.ts +36 -0
- package/dist/utils/olares-id.d.ts.map +1 -0
- package/dist/utils/olares-id.js +52 -0
- package/dist/utils/olares-id.js.map +1 -0
- package/dist/utils/tag-abi-codec.d.ts +69 -0
- package/dist/utils/tag-abi-codec.d.ts.map +1 -0
- package/dist/utils/tag-abi-codec.js +144 -0
- package/dist/utils/tag-abi-codec.js.map +1 -0
- package/dist/utils/tag-type-builder.d.ts +158 -0
- package/dist/utils/tag-type-builder.d.ts.map +1 -0
- package/dist/utils/tag-type-builder.js +410 -0
- package/dist/utils/tag-type-builder.js.map +1 -0
- package/examples/crypto-utilities.ts +140 -0
- package/examples/domain-context.ts +80 -0
- package/examples/generate-mnemonic.ts +149 -0
- package/examples/index.ts +1 -1
- package/examples/ip.ts +171 -0
- package/examples/legacy.ts +10 -10
- package/examples/list-wallets.ts +81 -0
- package/examples/olares-id-format.ts +197 -0
- package/examples/quasar-demo/.eslintrc.js +23 -0
- package/examples/quasar-demo/.quasar/app.js +43 -0
- package/examples/quasar-demo/.quasar/client-entry.js +38 -0
- package/examples/quasar-demo/.quasar/client-prefetch.js +130 -0
- package/examples/quasar-demo/.quasar/quasar-user-options.js +16 -0
- package/examples/quasar-demo/README.md +49 -0
- package/examples/quasar-demo/index.html +11 -0
- package/examples/quasar-demo/package-lock.json +6407 -0
- package/examples/quasar-demo/package.json +36 -0
- package/examples/quasar-demo/quasar.config.js +73 -0
- package/examples/quasar-demo/src/App.vue +13 -0
- package/examples/quasar-demo/src/css/app.scss +1 -0
- package/examples/quasar-demo/src/layouts/MainLayout.vue +21 -0
- package/examples/quasar-demo/src/pages/IndexPage.vue +905 -0
- package/examples/quasar-demo/src/router/index.ts +25 -0
- package/examples/quasar-demo/src/router/routes.ts +11 -0
- package/examples/quasar-demo/tsconfig.json +28 -0
- package/examples/register-subdomain.ts +152 -0
- package/examples/rsa-keypair.ts +148 -0
- package/examples/tag-builder.ts +235 -0
- package/examples/tag-management.ts +534 -0
- package/examples/tag-nested-tuple.ts +190 -0
- package/examples/tag-simple.ts +149 -0
- package/examples/tag-tagger.ts +217 -0
- package/examples/test-nested-tuple-conversion.ts +143 -0
- package/examples/test-type-bytes-parser.ts +70 -0
- package/examples/transfer-domain.ts +197 -0
- package/examples/wallet-management.ts +196 -0
- package/package.json +24 -15
- package/src/abi/RootResolver2ABI.ts +237 -0
- package/src/business/index.ts +1492 -0
- package/src/business/tag-context.ts +747 -0
- package/src/cli.ts +2772 -39
- package/src/debug.ts +17 -2
- package/src/index.ts +313 -17
- package/src/utils/crypto-utils.ts +459 -0
- package/src/utils/error-parser.ts +225 -0
- package/src/utils/olares-id.ts +49 -0
- package/src/utils/tag-abi-codec.ts +158 -0
- package/src/utils/tag-type-builder.ts +469 -0
- package/tsconfig.json +1 -1
package/TAG.md
ADDED
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
# Tag System Documentation
|
|
2
|
+
|
|
3
|
+
The Tag system is a powerful key-value storage mechanism for Olares domains. Each domain can have multiple tags with defined types, allowing structured metadata storage on the blockchain.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [Core Concepts](#core-concepts)
|
|
9
|
+
- [Supported Tag Types](#supported-tag-types)
|
|
10
|
+
- [SDK Usage](#sdk-usage)
|
|
11
|
+
- [CLI Usage](#cli-usage)
|
|
12
|
+
- [Permission Management](#permission-management)
|
|
13
|
+
- [Best Practices](#best-practices)
|
|
14
|
+
- [Examples](#examples)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
Tags are key-value pairs associated with a domain. Each tag has:
|
|
21
|
+
|
|
22
|
+
- **Name**: A unique identifier (string)
|
|
23
|
+
- **Type**: Defined using ABI types (e.g., `string`, `uint8`, `address[]`)
|
|
24
|
+
- **Value**: The actual data, encoded according to the type
|
|
25
|
+
- **Tagger**: An authorized address that can set/modify the tag value
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Core Concepts
|
|
30
|
+
|
|
31
|
+
### 1. Tag Definition
|
|
32
|
+
|
|
33
|
+
Before you can use a tag, you must **define** its type:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { TagTypeBuilder } from '@beclab/olaresid';
|
|
37
|
+
|
|
38
|
+
// Define a simple string tag
|
|
39
|
+
const emailType = TagTypeBuilder.string();
|
|
40
|
+
await tagCtx.defineTag('email', emailType);
|
|
41
|
+
|
|
42
|
+
// Define a uint8 tag
|
|
43
|
+
const ageType = TagTypeBuilder.uint(8);
|
|
44
|
+
await tagCtx.defineTag('age', ageType);
|
|
45
|
+
|
|
46
|
+
// Define an array tag
|
|
47
|
+
const linksType = TagTypeBuilder.array(TagTypeBuilder.string());
|
|
48
|
+
await tagCtx.defineTag('socialLinks', linksType);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Tagger Authorization
|
|
52
|
+
|
|
53
|
+
Each tag has a **tagger** - an Ethereum address authorized to set its value:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Set yourself as the tagger
|
|
57
|
+
const signerAddress = await signer.getAddress();
|
|
58
|
+
await domainCtx.setTagger('email', signerAddress);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Important:** You must set a tagger before you can set a tag's value. Only the tagger can modify the tag.
|
|
62
|
+
|
|
63
|
+
### 3. Tag Value Operations
|
|
64
|
+
|
|
65
|
+
Once defined and authorized, you can:
|
|
66
|
+
|
|
67
|
+
- **Set** a tag value
|
|
68
|
+
- **Get** a tag value (anyone can read)
|
|
69
|
+
- **Remove** a tag value (keeps the definition)
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Set value
|
|
73
|
+
await tagCtx.setTag('example.com', 'email', 'user@example.com');
|
|
74
|
+
|
|
75
|
+
// Get value
|
|
76
|
+
const email = await tagCtx.getTag('example.com', 'email');
|
|
77
|
+
|
|
78
|
+
// Remove value (definition remains)
|
|
79
|
+
await tagCtx.removeTag('example.com', 'email');
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Supported Tag Types
|
|
85
|
+
|
|
86
|
+
### Simple Types
|
|
87
|
+
|
|
88
|
+
| Type | Description | Example |
|
|
89
|
+
| ------------------- | ----------------- | ----------------- |
|
|
90
|
+
| `string` | UTF-8 text | `"Hello World"` |
|
|
91
|
+
| `uint8` - `uint256` | Unsigned integers | `42`, `255` |
|
|
92
|
+
| `int8` - `int256` | Signed integers | `-10`, `100` |
|
|
93
|
+
| `bool` | Boolean | `true`, `false` |
|
|
94
|
+
| `address` | Ethereum address | `"0x1234..."` |
|
|
95
|
+
| `bytes` | Dynamic bytes | `"0xabcd..."` |
|
|
96
|
+
| `bytes32` | Fixed 32 bytes | `"0x1234...abcd"` |
|
|
97
|
+
|
|
98
|
+
### Array Types
|
|
99
|
+
|
|
100
|
+
Any simple type can be made into a dynamic array:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// String array
|
|
104
|
+
TagTypeBuilder.array(TagTypeBuilder.string());
|
|
105
|
+
|
|
106
|
+
// Address array
|
|
107
|
+
TagTypeBuilder.array(TagTypeBuilder.address());
|
|
108
|
+
|
|
109
|
+
// Uint8 array
|
|
110
|
+
TagTypeBuilder.array(TagTypeBuilder.uint(8));
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Complex Tuple Types
|
|
114
|
+
|
|
115
|
+
For structured data, use tuples:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const userInfoType = TagTypeBuilder.tuple([
|
|
119
|
+
['name', TagTypeBuilder.string()],
|
|
120
|
+
['age', TagTypeBuilder.uint(8)],
|
|
121
|
+
['wallets', TagTypeBuilder.array(TagTypeBuilder.address())],
|
|
122
|
+
['verified', TagTypeBuilder.bool()]
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
await tagCtx.defineTag('userInfo', userInfoType);
|
|
126
|
+
|
|
127
|
+
// Set tuple value (automatic conversion!)
|
|
128
|
+
await tagCtx.setTag('example.com', 'userInfo', {
|
|
129
|
+
name: 'Alice',
|
|
130
|
+
age: 30,
|
|
131
|
+
wallets: ['0x1111...', '0x2222...'],
|
|
132
|
+
verified: true
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Nested Tuples
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Define nested tuple
|
|
140
|
+
const profileType = TagTypeBuilder.tuple({
|
|
141
|
+
name: TagTypeBuilder.string(),
|
|
142
|
+
details: TagTypeBuilder.tuple({
|
|
143
|
+
age: TagTypeBuilder.uint8(),
|
|
144
|
+
verified: TagTypeBuilder.bool()
|
|
145
|
+
}),
|
|
146
|
+
contact: TagTypeBuilder.tuple({
|
|
147
|
+
email: TagTypeBuilder.string(),
|
|
148
|
+
phone: TagTypeBuilder.string()
|
|
149
|
+
})
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await tagCtx.defineTag('profile', profileType);
|
|
153
|
+
|
|
154
|
+
// Set nested tuple (automatic conversion!)
|
|
155
|
+
await tagCtx.setTag('example.com', 'profile', {
|
|
156
|
+
name: 'Alice',
|
|
157
|
+
details: {
|
|
158
|
+
age: 30,
|
|
159
|
+
verified: true
|
|
160
|
+
},
|
|
161
|
+
contact: {
|
|
162
|
+
email: 'alice@example.com',
|
|
163
|
+
phone: '+1-555-0123'
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## SDK Usage
|
|
171
|
+
|
|
172
|
+
### Installation
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm install @beclab/olaresid
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Basic Setup
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import OlaresID, { TagTypeBuilder } from '@beclab/olaresid';
|
|
182
|
+
|
|
183
|
+
// Initialize
|
|
184
|
+
const olaresId = OlaresID.createTestnet(); // or createMainnet()
|
|
185
|
+
await olaresId.setSigner(privateKeyOrMnemonic);
|
|
186
|
+
|
|
187
|
+
// Get domain and tag contexts
|
|
188
|
+
const domain = olaresId.domain('example.com');
|
|
189
|
+
const tagCtx = domain.tag();
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Complete Workflow
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// 1. Define tag type
|
|
196
|
+
const bioType = TagTypeBuilder.string();
|
|
197
|
+
await tagCtx.defineTag('bio', bioType);
|
|
198
|
+
|
|
199
|
+
// 2. Set tagger (authorize yourself)
|
|
200
|
+
const signerAddress = await olaresId.signer.getAddress();
|
|
201
|
+
await domain.setTagger('bio', signerAddress);
|
|
202
|
+
|
|
203
|
+
// 3. Set tag value
|
|
204
|
+
await tagCtx.setTag('example.com', 'bio', 'Web3 developer');
|
|
205
|
+
|
|
206
|
+
// 4. Read tag value (anyone can read)
|
|
207
|
+
const bio = await tagCtx.getTag('example.com', 'bio');
|
|
208
|
+
console.log(bio); // "Web3 developer"
|
|
209
|
+
|
|
210
|
+
// 5. List all tags
|
|
211
|
+
const allTags = await domain.getAllTags();
|
|
212
|
+
console.log(allTags); // [{ name: 'bio', value: 'Web3 developer' }, ...]
|
|
213
|
+
|
|
214
|
+
// 6. List defined tag types
|
|
215
|
+
const definedTags = await domain.getDefinedTags();
|
|
216
|
+
console.log(definedTags); // ['bio', 'email', 'age', ...]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### High-Level API (Simplified)
|
|
220
|
+
|
|
221
|
+
For common operations, use the high-level API:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
const domain = olaresId.domain('example.com');
|
|
225
|
+
|
|
226
|
+
// Define and set in one step (using simplified API)
|
|
227
|
+
await domain.defineSimpleTag('email', 'string');
|
|
228
|
+
await domain.setTag('email', 'user@example.com');
|
|
229
|
+
|
|
230
|
+
// Get value
|
|
231
|
+
const email = await domain.getTag('email');
|
|
232
|
+
|
|
233
|
+
// Remove value
|
|
234
|
+
await domain.removeTag('email');
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Array Operations
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Define array type
|
|
241
|
+
const linksType = TagTypeBuilder.array(TagTypeBuilder.string());
|
|
242
|
+
await tagCtx.defineTag('socialLinks', linksType);
|
|
243
|
+
await domain.setTagger('socialLinks', signerAddress);
|
|
244
|
+
|
|
245
|
+
// Set array value
|
|
246
|
+
await tagCtx.setTag('example.com', 'socialLinks', [
|
|
247
|
+
'https://twitter.com/user',
|
|
248
|
+
'https://github.com/user'
|
|
249
|
+
]);
|
|
250
|
+
|
|
251
|
+
// Get array value
|
|
252
|
+
const links = await tagCtx.getTag('example.com', 'socialLinks');
|
|
253
|
+
console.log(links); // ['https://twitter.com/user', 'https://github.com/user']
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Error Handling
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
try {
|
|
260
|
+
await tagCtx.defineTag('email', emailType);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (error.message.includes('already been defined')) {
|
|
263
|
+
console.log('Tag already exists, skipping definition');
|
|
264
|
+
} else {
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## CLI Usage
|
|
273
|
+
|
|
274
|
+
The CLI provides simple commands for basic tag operations. For advanced usage (complex types, tuple operations), use the SDK.
|
|
275
|
+
|
|
276
|
+
### Define Tag Type
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Simple types
|
|
280
|
+
npx ts-node src/cli.ts tag define example.com email string
|
|
281
|
+
npx ts-node src/cli.ts tag define example.com age uint8
|
|
282
|
+
npx ts-node src/cli.ts tag define example.com verified bool
|
|
283
|
+
|
|
284
|
+
# Array types (must be quoted!)
|
|
285
|
+
npx ts-node src/cli.ts tag define example.com wallets "address[]"
|
|
286
|
+
npx ts-node src/cli.ts tag define example.com links "string[]"
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Set Tagger
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Set tagger address
|
|
293
|
+
npx ts-node src/cli.ts tag set-tagger example.com email 0xYOUR_ADDRESS
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Set Tag Value
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# String value
|
|
300
|
+
npx ts-node src/cli.ts tag set example.com email "user@example.com"
|
|
301
|
+
|
|
302
|
+
# Number value
|
|
303
|
+
npx ts-node src/cli.ts tag set example.com age 30
|
|
304
|
+
|
|
305
|
+
# Boolean value
|
|
306
|
+
npx ts-node src/cli.ts tag set example.com verified true
|
|
307
|
+
|
|
308
|
+
# Array value (use JSON, must be quoted!)
|
|
309
|
+
npx ts-node src/cli.ts tag set example.com links '["https://twitter.com","https://github.com"]'
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Get Tag Value
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
# Read-only, no authentication required
|
|
316
|
+
npx ts-node src/cli.ts tag get example.com email
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### List Tags
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# List all tags with values
|
|
323
|
+
npx ts-node src/cli.ts tag list example.com
|
|
324
|
+
|
|
325
|
+
# List all defined tag types
|
|
326
|
+
npx ts-node src/cli.ts tag list-defined example.com
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Remove Tag Value
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
# Remove value (definition remains)
|
|
333
|
+
npx ts-node src/cli.ts tag remove example.com email
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Environment Variables
|
|
337
|
+
|
|
338
|
+
Write operations require authentication:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
export PRIVATE_KEY_OR_MNEMONIC="0xYOUR_PRIVATE_KEY"
|
|
342
|
+
# OR
|
|
343
|
+
export PRIVATE_KEY_OR_MNEMONIC="your twelve word mnemonic phrase here"
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Permission Management
|
|
349
|
+
|
|
350
|
+
### Tagger Role
|
|
351
|
+
|
|
352
|
+
The **tagger** is the only address authorized to set/modify a tag's value. The domain owner can set or change the tagger at any time.
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// Set tagger (only domain owner can do this)
|
|
356
|
+
await domain.setTagger('email', '0xTAGGER_ADDRESS');
|
|
357
|
+
|
|
358
|
+
// Get current tagger
|
|
359
|
+
const tagger = await tagCtx.getTagger('email');
|
|
360
|
+
console.log(tagger); // "0xTAGGER_ADDRESS"
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Authorization Flow
|
|
364
|
+
|
|
365
|
+
1. **Domain Owner** defines tag type → calls `defineTag()`
|
|
366
|
+
2. **Domain Owner** sets tagger → calls `setTagger(tagName, taggerAddress)`
|
|
367
|
+
3. **Tagger** can now set/modify values → calls `setTag()`, `removeTag()`
|
|
368
|
+
4. **Anyone** can read values → calls `getTag()`
|
|
369
|
+
|
|
370
|
+
### Common Patterns
|
|
371
|
+
|
|
372
|
+
**Pattern 1: Owner manages their own tags**
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
const ownerAddress = await signer.getAddress();
|
|
376
|
+
await domain.setTagger('bio', ownerAddress);
|
|
377
|
+
await tagCtx.setTag('example.com', 'bio', 'My biography');
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Pattern 2: Delegate to a contract**
|
|
381
|
+
|
|
382
|
+
Delegating tagger permissions to a smart contract allows for more complex logic and automation:
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
const CONTRACT_ADDRESS = '0x1234...'; // Your smart contract address
|
|
386
|
+
await domain.setTagger('reputation', CONTRACT_ADDRESS);
|
|
387
|
+
// Now the contract can update the reputation tag with custom logic
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Benefits of using contracts as taggers:**
|
|
391
|
+
|
|
392
|
+
- Implement complex authorization logic (multi-sig, time-locks, etc.)
|
|
393
|
+
- Enable automated tag updates based on on-chain events
|
|
394
|
+
- Create composable tag management systems
|
|
395
|
+
- Enforce business rules programmatically
|
|
396
|
+
|
|
397
|
+
**Reference Implementations:**
|
|
398
|
+
|
|
399
|
+
For real-world examples, see the [did-contracts/src/taggers](../../did-contracts/src/taggers/) directory, which contains production tagger contracts currently in use.
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Best Practices
|
|
404
|
+
|
|
405
|
+
### 1. Handle RedefinedTag Errors
|
|
406
|
+
|
|
407
|
+
Tags can only be defined once. Always check if a tag exists:
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
try {
|
|
411
|
+
await tagCtx.defineTag('email', emailType);
|
|
412
|
+
} catch (error) {
|
|
413
|
+
if (error.message.includes('already been defined')) {
|
|
414
|
+
console.log('Tag already exists, skipping');
|
|
415
|
+
} else {
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### 2. Always Set Tagger After Defining
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
// ✅ Good
|
|
425
|
+
await tagCtx.defineTag('email', emailType);
|
|
426
|
+
await domain.setTagger('email', signerAddress);
|
|
427
|
+
await tagCtx.setTag('example.com', 'email', 'user@example.com');
|
|
428
|
+
|
|
429
|
+
// ❌ Bad - will fail with "Unauthorized"
|
|
430
|
+
await tagCtx.defineTag('email', emailType);
|
|
431
|
+
await tagCtx.setTag('example.com', 'email', 'user@example.com'); // No tagger set!
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 3. Wait for Blockchain Indexing
|
|
435
|
+
|
|
436
|
+
After write operations, allow time for nodes to index:
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
await tagCtx.setTag('example.com', 'email', 'user@example.com');
|
|
440
|
+
await new Promise(resolve => setTimeout(resolve, 3000)); // Wait 3 seconds
|
|
441
|
+
const email = await tagCtx.getTag('example.com', 'email');
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### 4. Validate Input Types
|
|
445
|
+
|
|
446
|
+
The blockchain will reject invalid types:
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
// ❌ Wrong type
|
|
450
|
+
await tagCtx.setTag('example.com', 'age', 'thirty'); // Expected number
|
|
451
|
+
|
|
452
|
+
// ✅ Correct type
|
|
453
|
+
await tagCtx.setTag('example.com', 'age', 30);
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## Examples
|
|
459
|
+
|
|
460
|
+
### Example 1: User Profile
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
// Define tags
|
|
464
|
+
await tagCtx.defineTag('bio', TagTypeBuilder.string());
|
|
465
|
+
await tagCtx.defineTag('followers', TagTypeBuilder.uint(256));
|
|
466
|
+
await tagCtx.defineTag('verified', TagTypeBuilder.bool());
|
|
467
|
+
await tagCtx.defineTag(
|
|
468
|
+
'socialLinks',
|
|
469
|
+
TagTypeBuilder.array(TagTypeBuilder.string())
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
// Set tagger
|
|
473
|
+
const signer = await olaresId.signer.getAddress();
|
|
474
|
+
await domain.setTagger('bio', signer);
|
|
475
|
+
await domain.setTagger('followers', signer);
|
|
476
|
+
await domain.setTagger('verified', signer);
|
|
477
|
+
await domain.setTagger('socialLinks', signer);
|
|
478
|
+
|
|
479
|
+
// Set values
|
|
480
|
+
await tagCtx.setTag('alice.com', 'bio', 'Web3 enthusiast');
|
|
481
|
+
await tagCtx.setTag('alice.com', 'followers', 1350);
|
|
482
|
+
await tagCtx.setTag('alice.com', 'verified', true);
|
|
483
|
+
await tagCtx.setTag('alice.com', 'socialLinks', [
|
|
484
|
+
'https://twitter.com/alice',
|
|
485
|
+
'https://github.com/alice'
|
|
486
|
+
]);
|
|
487
|
+
|
|
488
|
+
// Read all tags
|
|
489
|
+
const tags = await domain.getAllTags();
|
|
490
|
+
console.log(tags);
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Example 2: NFT Metadata
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
// Define NFT metadata tags
|
|
497
|
+
const nftType = TagTypeBuilder.tuple([
|
|
498
|
+
['tokenId', TagTypeBuilder.uint(256)],
|
|
499
|
+
['name', TagTypeBuilder.string()],
|
|
500
|
+
['description', TagTypeBuilder.string()],
|
|
501
|
+
['image', TagTypeBuilder.string()],
|
|
502
|
+
['attributes', TagTypeBuilder.array(TagTypeBuilder.string())]
|
|
503
|
+
]);
|
|
504
|
+
|
|
505
|
+
await tagCtx.defineTag('nftMetadata', nftType);
|
|
506
|
+
await domain.setTagger('nftMetadata', signerAddress);
|
|
507
|
+
|
|
508
|
+
// Set NFT metadata
|
|
509
|
+
await tagCtx.setTag('nft.com', 'nftMetadata', {
|
|
510
|
+
tokenId: 1,
|
|
511
|
+
name: 'Cool NFT #1',
|
|
512
|
+
description: 'A very cool NFT',
|
|
513
|
+
image: 'ipfs://QmXxx...',
|
|
514
|
+
attributes: ['rare', 'animated', 'special']
|
|
515
|
+
});
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Example 3: Service Configuration
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
// Define service config tags
|
|
522
|
+
await tagCtx.defineTag('apiEndpoint', TagTypeBuilder.string());
|
|
523
|
+
await tagCtx.defineTag(
|
|
524
|
+
'rpcNodes',
|
|
525
|
+
TagTypeBuilder.array(TagTypeBuilder.string())
|
|
526
|
+
);
|
|
527
|
+
await tagCtx.defineTag('maxRetries', TagTypeBuilder.uint(8));
|
|
528
|
+
await tagCtx.defineTag('enabled', TagTypeBuilder.bool());
|
|
529
|
+
|
|
530
|
+
// Delegate tagger to service admin
|
|
531
|
+
const SERVICE_ADMIN = '0x1234...';
|
|
532
|
+
await domain.setTagger('apiEndpoint', SERVICE_ADMIN);
|
|
533
|
+
await domain.setTagger('rpcNodes', SERVICE_ADMIN);
|
|
534
|
+
await domain.setTagger('maxRetries', SERVICE_ADMIN);
|
|
535
|
+
await domain.setTagger('enabled', SERVICE_ADMIN);
|
|
536
|
+
|
|
537
|
+
// Service admin sets config
|
|
538
|
+
await tagCtx.setTag('service.com', 'apiEndpoint', 'https://api.example.com');
|
|
539
|
+
await tagCtx.setTag('service.com', 'rpcNodes', [
|
|
540
|
+
'https://rpc1.example.com',
|
|
541
|
+
'https://rpc2.example.com'
|
|
542
|
+
]);
|
|
543
|
+
await tagCtx.setTag('service.com', 'maxRetries', 3);
|
|
544
|
+
await tagCtx.setTag('service.com', 'enabled', true);
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## See Also
|
|
550
|
+
|
|
551
|
+
- **[SDK Examples](./examples/)** - Complete code examples
|
|
552
|
+
- **[CLI Documentation](./CLI.md#tag-management-commands)** - Full CLI reference
|
|
553
|
+
- **[Main README](./README.md)** - General documentation
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## Troubleshooting
|
|
558
|
+
|
|
559
|
+
### Error: "Tag already exists"
|
|
560
|
+
|
|
561
|
+
**Solution:** Tag definitions are immutable. You cannot redefine a tag. Check if it exists first.
|
|
562
|
+
|
|
563
|
+
### Error: "Unauthorized"
|
|
564
|
+
|
|
565
|
+
**Solution:** You haven't set a tagger, or you're not the tagger. Call `setTagger()` first.
|
|
566
|
+
|
|
567
|
+
### Error: "Invalid tag operation"
|
|
568
|
+
|
|
569
|
+
**Solution:** You're trying to remove a tag that has no value, or performing an unsupported operation.
|
|
570
|
+
|
|
571
|
+
### Error: "Tuple field count mismatch"
|
|
572
|
+
|
|
573
|
+
**Solution:** Ensure object keys match the tuple field definition order and count. Objects are automatically converted to arrays based on the ABI type structure.
|
|
574
|
+
|
|
575
|
+
### Shell Error: "no matches found: address[]"
|
|
576
|
+
|
|
577
|
+
**Solution:** Quote array types in the shell: `"address[]"` instead of `address[]`.
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## Contract Reference
|
|
582
|
+
|
|
583
|
+
Tag operations interact with the following contracts:
|
|
584
|
+
|
|
585
|
+
- **TerminusDID**: Tag definition, tagger management
|
|
586
|
+
- **TagRegistry**: Core tag storage and operations
|
|
587
|
+
- **RootResolver**: Legacy tag operations (compatibility)
|
|
588
|
+
|
|
589
|
+
For contract details, see the [did-contracts](../../did-contracts/) repository.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
abi: ({
|
|
3
|
+
inputs: {
|
|
4
|
+
internalType: string;
|
|
5
|
+
name: string;
|
|
6
|
+
type: string;
|
|
7
|
+
}[];
|
|
8
|
+
name: string;
|
|
9
|
+
type: string;
|
|
10
|
+
outputs?: undefined;
|
|
11
|
+
stateMutability?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
inputs: ({
|
|
14
|
+
components: {
|
|
15
|
+
internalType: string;
|
|
16
|
+
name: string;
|
|
17
|
+
type: string;
|
|
18
|
+
}[];
|
|
19
|
+
internalType: string;
|
|
20
|
+
name: string;
|
|
21
|
+
type: string;
|
|
22
|
+
} | {
|
|
23
|
+
internalType: string;
|
|
24
|
+
name: string;
|
|
25
|
+
type: string;
|
|
26
|
+
components?: undefined;
|
|
27
|
+
})[];
|
|
28
|
+
name: string;
|
|
29
|
+
outputs: never[];
|
|
30
|
+
stateMutability: string;
|
|
31
|
+
type: string;
|
|
32
|
+
} | {
|
|
33
|
+
inputs: {
|
|
34
|
+
internalType: string;
|
|
35
|
+
name: string;
|
|
36
|
+
type: string;
|
|
37
|
+
}[];
|
|
38
|
+
name: string;
|
|
39
|
+
outputs: {
|
|
40
|
+
components: {
|
|
41
|
+
internalType: string;
|
|
42
|
+
name: string;
|
|
43
|
+
type: string;
|
|
44
|
+
}[];
|
|
45
|
+
internalType: string;
|
|
46
|
+
name: string;
|
|
47
|
+
type: string;
|
|
48
|
+
}[];
|
|
49
|
+
stateMutability: string;
|
|
50
|
+
type: string;
|
|
51
|
+
})[];
|
|
52
|
+
};
|
|
53
|
+
export default _default;
|
|
54
|
+
//# sourceMappingURL=RootResolver2ABI.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RootResolver2ABI.d.ts","sourceRoot":"","sources":["../../src/abi/RootResolver2ABI.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wBA4OE"}
|