@ethereum-entity-registry/sdk 0.1.0 → 0.2.1
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/README.md +345 -0
- package/package.json +17 -1
package/README.md
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# @ethereum-entity-registry/sdk
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ethereum-entity-registry/sdk)
|
|
4
|
+
|
|
5
|
+
TypeScript SDK and React hooks for the [Ethereum Entity Registry](https://github.com/ethereum-entity-registry) — a shared on-chain registry that maps off-chain identifiers (GitHub repos, DNS domains) to Ethereum addresses.
|
|
6
|
+
|
|
7
|
+
Every identifier gets a deterministic deposit address before its owner has ever touched Ethereum. Funds accumulate there until the owner claims and takes control.
|
|
8
|
+
|
|
9
|
+
> **Status:** Research prototype. Contracts are not audited. Do not use in production.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @ethereum-entity-registry/sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Peer dependencies**
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install viem wagmi @tanstack/react-query sonner
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { EntityRegistrySDK } from "@ethereum-entity-registry/sdk";
|
|
27
|
+
|
|
28
|
+
// Read-only (no wallet)
|
|
29
|
+
const sdk = new EntityRegistrySDK();
|
|
30
|
+
|
|
31
|
+
// With a wallet for write operations
|
|
32
|
+
const sdk = new EntityRegistrySDK(walletClient);
|
|
33
|
+
|
|
34
|
+
// Explicit chain (defaults to chain from wallet, or hardhat locally)
|
|
35
|
+
const sdk = new EntityRegistrySDK(walletClient, 84532); // Base Sepolia
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Supported chains**
|
|
39
|
+
|
|
40
|
+
| Chain | ID |
|
|
41
|
+
|---|---|
|
|
42
|
+
| Mainnet | `1` |
|
|
43
|
+
| Sepolia | `11155111` |
|
|
44
|
+
| Base | `8453` |
|
|
45
|
+
| Base Sepolia | `84532` |
|
|
46
|
+
| Hardhat (local) | `31337` |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## SDK Reference
|
|
51
|
+
|
|
52
|
+
### `sdk.registry`
|
|
53
|
+
|
|
54
|
+
#### `resolve(input, token?)`
|
|
55
|
+
|
|
56
|
+
Resolve any identifier string to its on-chain state.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const state = await sdk.registry.resolve("github.com/org/repo");
|
|
60
|
+
// state.id — bytes32 identifier
|
|
61
|
+
// state.depositAddress — deterministic account address (fund here)
|
|
62
|
+
// state.owner — registered owner, or null if unclaimed
|
|
63
|
+
|
|
64
|
+
// Pass a token address to include the balance
|
|
65
|
+
const state = await sdk.registry.resolve("github.com/org/repo", tokenAddress);
|
|
66
|
+
// state.balance — ERC-20 balance at the deposit address
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
All of these formats are accepted:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
sdk.registry.resolve("github:org/repo");
|
|
73
|
+
sdk.registry.resolve("https://github.com/org/repo");
|
|
74
|
+
sdk.registry.resolve("example.com");
|
|
75
|
+
sdk.registry.resolve("dns:example.com");
|
|
76
|
+
sdk.registry.resolve("npmjs.com/package/foo");
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### `ownerOf(id)`
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const owner = await sdk.registry.ownerOf(id); // Address | null
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### `predictAddress(id)`
|
|
86
|
+
|
|
87
|
+
Compute the deterministic deposit address without an RPC call.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const address = await sdk.registry.predictAddress(id);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### `toId(namespace, canonicalString)`
|
|
94
|
+
|
|
95
|
+
Derive the bytes32 identifier for a namespace/value pair.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
const id = await sdk.registry.toId("github", "org/repo");
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### `claim(input, proof)`
|
|
102
|
+
|
|
103
|
+
Submit a verified proof to register ownership on-chain.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
await sdk.registry.claim("github.com/org/repo", proofBytes);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### `revoke(input)`
|
|
110
|
+
|
|
111
|
+
Release ownership of a claimed identifier.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
await sdk.registry.revoke("github.com/org/repo");
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### `linkIds(primaryId, aliasIds)` / `unlinkIds(primaryId, aliasIds)`
|
|
118
|
+
|
|
119
|
+
Create or remove aliases between identifiers (e.g. link a GitHub org to a domain).
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
await sdk.registry.linkIds(primaryId, [aliasId1, aliasId2]);
|
|
123
|
+
await sdk.registry.unlinkIds(primaryId, [aliasId1]);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### `deployAccount(id)`
|
|
127
|
+
|
|
128
|
+
Explicitly deploy the identity account contract for an identifier (auto-deployed on first `execute` otherwise).
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
await sdk.registry.deployAccount(id);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### `sdk.account`
|
|
137
|
+
|
|
138
|
+
#### `execute(accountAddress, target, data, value?)`
|
|
139
|
+
|
|
140
|
+
Call any contract from the identity account. Only the registered owner can call this.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
await sdk.account.execute(accountAddress, target, data);
|
|
144
|
+
await sdk.account.execute(accountAddress, target, data, parseEther("0.1"));
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### `encodeERC20Transfer(token, recipient, amount)`
|
|
148
|
+
|
|
149
|
+
Encode an ERC-20 transfer to be executed via the identity account.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const { target, data } = sdk.account.encodeERC20Transfer(
|
|
153
|
+
tokenAddress,
|
|
154
|
+
recipient,
|
|
155
|
+
amount,
|
|
156
|
+
);
|
|
157
|
+
await sdk.account.execute(state.depositAddress, target, data);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### `encodeWarehouseWithdraw(warehouse, account, token)`
|
|
161
|
+
|
|
162
|
+
Encode a Splits Warehouse withdrawal.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const call = sdk.account.encodeWarehouseWithdraw(
|
|
166
|
+
warehouseAddress,
|
|
167
|
+
state.depositAddress,
|
|
168
|
+
tokenAddress,
|
|
169
|
+
);
|
|
170
|
+
await sdk.account.execute(state.depositAddress, call.target, call.data);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### Utility functions
|
|
176
|
+
|
|
177
|
+
#### `parseUrl(input)`
|
|
178
|
+
|
|
179
|
+
Parse any URL or namespace-prefixed string into its components.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { parseUrl } from "@ethereum-entity-registry/sdk";
|
|
183
|
+
|
|
184
|
+
parseUrl("https://github.com/org/repo");
|
|
185
|
+
// → { namespace: "github", canonicalString: "org/repo", formatted: "github:org/repo" }
|
|
186
|
+
|
|
187
|
+
parseUrl("example.com");
|
|
188
|
+
// → { namespace: "dns", canonicalString: "example.com", formatted: "dns:example.com" }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
#### `toId(namespace, canonicalString)`
|
|
192
|
+
|
|
193
|
+
Pure local computation of the bytes32 identifier — no RPC call needed.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
import { toId } from "@ethereum-entity-registry/sdk";
|
|
197
|
+
|
|
198
|
+
const id = toId("github", "org/repo");
|
|
199
|
+
// keccak256(abi.encode("github", "org/repo"))
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## React Hooks
|
|
205
|
+
|
|
206
|
+
### Setup
|
|
207
|
+
|
|
208
|
+
Wrap your app with `EntityRegistryProvider`:
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
import { EntityRegistryProvider } from "@ethereum-entity-registry/sdk";
|
|
212
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
213
|
+
|
|
214
|
+
const queryClient = new QueryClient();
|
|
215
|
+
|
|
216
|
+
function App() {
|
|
217
|
+
return (
|
|
218
|
+
<QueryClientProvider client={queryClient}>
|
|
219
|
+
<EntityRegistryProvider walletClient={walletClient}>
|
|
220
|
+
{/* ... */}
|
|
221
|
+
</EntityRegistryProvider>
|
|
222
|
+
</QueryClientProvider>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Read hooks
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
import {
|
|
231
|
+
useOwnerOf,
|
|
232
|
+
usePredictAddress,
|
|
233
|
+
useToId,
|
|
234
|
+
} from "@ethereum-entity-registry/sdk";
|
|
235
|
+
|
|
236
|
+
// Resolve owner of an identifier
|
|
237
|
+
const { data: owner } = useOwnerOf(id);
|
|
238
|
+
|
|
239
|
+
// Get the deterministic deposit address
|
|
240
|
+
const { data: depositAddress } = usePredictAddress(id);
|
|
241
|
+
|
|
242
|
+
// Compute bytes32 id from namespace + string
|
|
243
|
+
const { data: id } = useToId("github", "org/repo");
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Write hooks
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
import {
|
|
250
|
+
useClaim,
|
|
251
|
+
useRevoke,
|
|
252
|
+
useLinkIds,
|
|
253
|
+
useUnlinkIds,
|
|
254
|
+
useDeployAccount,
|
|
255
|
+
useExecute,
|
|
256
|
+
} from "@ethereum-entity-registry/sdk";
|
|
257
|
+
|
|
258
|
+
function ClaimButton({ input, proof }) {
|
|
259
|
+
const claim = useClaim();
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<button
|
|
263
|
+
onClick={() => claim.mutate({ input, proof })}
|
|
264
|
+
disabled={claim.isPending}
|
|
265
|
+
>
|
|
266
|
+
Claim
|
|
267
|
+
</button>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function ExecuteButton({ accountAddress, target, data }) {
|
|
272
|
+
const execute = useExecute();
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
<button onClick={() => execute.mutate({ accountAddress, target, data })}>
|
|
276
|
+
Execute
|
|
277
|
+
</button>
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Claim Flow
|
|
285
|
+
|
|
286
|
+
### GitHub
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
// 1. Redirect to the OAuth gateway
|
|
290
|
+
window.location.href = `/claim/github?owner=org&repo=repo&claimant=${address}`;
|
|
291
|
+
|
|
292
|
+
// 2. After OAuth, the gateway returns with a signed proof
|
|
293
|
+
const proof = new URLSearchParams(window.location.search).get("proof");
|
|
294
|
+
|
|
295
|
+
// 3. Submit on-chain
|
|
296
|
+
await sdk.registry.claim("github.com/org/repo", proof);
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### DNS
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
// 1. Add a TXT record to your domain:
|
|
303
|
+
// _eth-entity.example.com → "0xYourAddress"
|
|
304
|
+
|
|
305
|
+
// 2. Request a proof from the signing service
|
|
306
|
+
const res = await fetch("/api/proof/dns", {
|
|
307
|
+
method: "POST",
|
|
308
|
+
body: JSON.stringify({ domain: "example.com", claimant: address }),
|
|
309
|
+
});
|
|
310
|
+
const { proof } = await res.json();
|
|
311
|
+
|
|
312
|
+
// 3. Submit on-chain
|
|
313
|
+
await sdk.registry.claim("example.com", proof);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## On-Chain Integration (Solidity)
|
|
319
|
+
|
|
320
|
+
```solidity
|
|
321
|
+
import {IEntityRegistry} from "@ethereum-entity-registry/contracts/contracts/IEntityRegistry.sol";
|
|
322
|
+
|
|
323
|
+
address registry = 0x081a5907ab0A77fCc84cf217B62730b9341Ee687; // Base Sepolia
|
|
324
|
+
|
|
325
|
+
bytes32 id = keccak256(abi.encode("github", "org/repo"));
|
|
326
|
+
address owner = IEntityRegistry(registry).ownerOf(id);
|
|
327
|
+
|
|
328
|
+
// ownerOf resolves through aliases transparently
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Deployed addresses**
|
|
332
|
+
|
|
333
|
+
| Network | Registry |
|
|
334
|
+
|---|---|
|
|
335
|
+
| Base Sepolia | `0x081a5907ab0A77fCc84cf217B62730b9341Ee687` |
|
|
336
|
+
| Sepolia | see `deployments.json` |
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Links
|
|
341
|
+
|
|
342
|
+
- [GitHub](https://github.com/ethereum-entity-registry)
|
|
343
|
+
- [Documentation](https://ethereum-entity-registry.vercel.app/docs)
|
|
344
|
+
- [npm](https://www.npmjs.com/package/@ethereum-entity-registry/sdk)
|
|
345
|
+
- [Contracts](https://www.npmjs.com/package/@ethereum-entity-registry/contracts)
|
package/package.json
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ethereum-entity-registry/sdk",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"description": "TypeScript SDK and React hooks for the Ethereum Entity Registry",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/carlbarrdahl/ethereum-canonical-registry",
|
|
9
|
+
"directory": "packages/sdk"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/carlbarrdahl/ethereum-canonical-registry#readme",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"ethereum",
|
|
14
|
+
"registry",
|
|
15
|
+
"identity",
|
|
16
|
+
"github",
|
|
17
|
+
"dns",
|
|
18
|
+
"viem",
|
|
19
|
+
"wagmi"
|
|
20
|
+
],
|
|
5
21
|
"files": [
|
|
6
22
|
"dist"
|
|
7
23
|
],
|