@sorandomains/holder 0.1.0 → 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/README.md +2 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +41 -19
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -28,11 +28,12 @@ await me.setProfile("alice.nova", { // the standard keys every wallet reads
|
|
|
28
28
|
| --- | --- |
|
|
29
29
|
| `setRecord` | Point your name's explicit resolver record at any address (generation-gated — stops resolving the moment the name changes hands) |
|
|
30
30
|
| `setAddress` | Re-point the built-in (Registrar) resolution target |
|
|
31
|
-
| `setText` / `setProfile` | Publish text records; `setProfile` writes the standard `PROFILE_KEYS` (one transaction per key) |
|
|
31
|
+
| `setText` / `setProfile` / `clearText` | Publish text records; `setProfile` writes the standard `PROFILE_KEYS` (one transaction per key); records are overwrite-only on chain — `clearText` retracts by writing the empty value standard readers treat as unset |
|
|
32
32
|
| `setReverse` / `clearReverse` | Claim your address→name reverse record — the contract refuses names that don't already resolve to you (`ForwardMismatch`) |
|
|
33
33
|
| `setPrimary` / `clearPrimary` | Your one cross-namespace display name, re-verified on chain at every read |
|
|
34
34
|
| `proposeNameTransfer` / `acceptNameTransfer` / `cancelNameTransfer` | Two-step, accept-to-move name transfers (policy-gated) |
|
|
35
35
|
| `pendingNameTransfer` | Read the pending proposal |
|
|
36
|
+
| `registrarOf` / `resolverOf` | Discover the namespace's attested Registrar / resolver pointer |
|
|
36
37
|
|
|
37
38
|
Everything is holder-authorized **on chain** — the Resolver checks you hold
|
|
38
39
|
the name right now, reverse and primary claims are authorized by the address
|
package/dist/index.d.ts
CHANGED
|
@@ -158,6 +158,11 @@ export declare class SoranHolder {
|
|
|
158
158
|
* and the contract enforces that the name's forward record already
|
|
159
159
|
* resolves to you (ForwardMismatch otherwise): a reverse claim on a name
|
|
160
160
|
* that doesn't point back at you is spoofing, and the chain refuses it.
|
|
161
|
+
*
|
|
162
|
+
* NOTE the forward proof must be the RESOLVER's OWN record — the
|
|
163
|
+
* Registrar's built-in target (which `lookup.resolve` also honors for
|
|
164
|
+
* fresh names) does not count. On a freshly issued name, call
|
|
165
|
+
* `setRecord(name, yourAddress)` first, then `setReverse(name)`.
|
|
161
166
|
*/
|
|
162
167
|
setReverse(name: string): Promise<Submitted>;
|
|
163
168
|
/** Remove your reverse record on a namespace's resolver. */
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* before signing. Operations on one instance are serialized so concurrent
|
|
31
31
|
* calls cannot race the account sequence number.
|
|
32
32
|
*/
|
|
33
|
-
import { Account, Address, BASE_FEE, Contract, Keypair, Networks, Operation, TransactionBuilder, hash, nativeToScVal, rpc, scValToNative,
|
|
33
|
+
import { Account, Address, BASE_FEE, Contract, Keypair, Networks, Operation, TransactionBuilder, hash, nativeToScVal, rpc, scValToNative, } from "@stellar/stellar-sdk";
|
|
34
34
|
// ---------------------------------------------------------------------------
|
|
35
35
|
// Deployments
|
|
36
36
|
// ---------------------------------------------------------------------------
|
|
@@ -167,6 +167,11 @@ function concatBytes(...parts) {
|
|
|
167
167
|
}
|
|
168
168
|
return out;
|
|
169
169
|
}
|
|
170
|
+
/** Browser-safe hex (SDK17: hash()/XDR bytes are Uint8Array, whose toString()
|
|
171
|
+
* ignores a radix — and this package forbids a bare `Buffer` in the bundle). */
|
|
172
|
+
function toHex(b) {
|
|
173
|
+
return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
174
|
+
}
|
|
170
175
|
function namehash(namespace) {
|
|
171
176
|
const labelHash = new Uint8Array(hash(utf8(namespace)));
|
|
172
177
|
return new Uint8Array(hash(concatBytes(new Uint8Array(32), labelHash)));
|
|
@@ -322,12 +327,26 @@ export class SoranHolder {
|
|
|
322
327
|
* and the contract enforces that the name's forward record already
|
|
323
328
|
* resolves to you (ForwardMismatch otherwise): a reverse claim on a name
|
|
324
329
|
* that doesn't point back at you is spoofing, and the chain refuses it.
|
|
330
|
+
*
|
|
331
|
+
* NOTE the forward proof must be the RESOLVER's OWN record — the
|
|
332
|
+
* Registrar's built-in target (which `lookup.resolve` also honors for
|
|
333
|
+
* fresh names) does not count. On a freshly issued name, call
|
|
334
|
+
* `setRecord(name, yourAddress)` first, then `setReverse(name)`.
|
|
325
335
|
*/
|
|
326
336
|
async setReverse(name) {
|
|
327
337
|
const { namespace } = parseName(name);
|
|
328
338
|
const resolverId = await this.resolverOf(namespace);
|
|
329
339
|
const pub = await this.signer.publicKey();
|
|
330
|
-
|
|
340
|
+
let r;
|
|
341
|
+
try {
|
|
342
|
+
r = await this.invoke(resolverId, "set_reverse", [addrArg(pub), nativeToScVal(name.toLowerCase(), { type: "string" })], RESOLVER_ERRORS);
|
|
343
|
+
}
|
|
344
|
+
catch (e) {
|
|
345
|
+
if (e instanceof HolderError && e.codeName === "ForwardMismatch") {
|
|
346
|
+
throw new HolderError(`${e.message} — the resolver only accepts its OWN forward record as proof; if this name still resolves via the Registrar's built-in target, call setRecord(name, yourAddress) first, then retry setReverse`, e.contractId, e.fn, e.code, e.codeName, e.txHash);
|
|
347
|
+
}
|
|
348
|
+
throw e;
|
|
349
|
+
}
|
|
331
350
|
return { hash: r.hash, ledger: r.ledger };
|
|
332
351
|
}
|
|
333
352
|
/** Remove your reverse record on a namespace's resolver. */
|
|
@@ -473,12 +492,12 @@ export class SoranHolder {
|
|
|
473
492
|
assertSatisfiableAuth(prepared, pub, contractId, fn) {
|
|
474
493
|
const op = prepared.operations[0];
|
|
475
494
|
for (const entry of op?.auth ?? []) {
|
|
476
|
-
const cred = entry.credentials
|
|
477
|
-
if (cred.
|
|
495
|
+
const cred = entry.credentials;
|
|
496
|
+
if (cred.type !== "sorobanCredentialsAddress")
|
|
478
497
|
continue;
|
|
479
498
|
let required;
|
|
480
499
|
try {
|
|
481
|
-
required = Address.fromScAddress(cred.address
|
|
500
|
+
required = Address.fromScAddress(cred.address.address).toString();
|
|
482
501
|
}
|
|
483
502
|
catch {
|
|
484
503
|
continue;
|
|
@@ -509,21 +528,24 @@ export class SoranHolder {
|
|
|
509
528
|
.setTimeout(this.timeoutSecs)
|
|
510
529
|
.build();
|
|
511
530
|
let tx = build(await this.sourceAccount(pub, fn));
|
|
512
|
-
|
|
531
|
+
// (SDK17/P28) useUpgradedAuth=false keeps legacy V1 SorobanCredentials rather
|
|
532
|
+
// than CAP-71 address-bound V2 — valid against P27 (pre-vote) and P28 (post),
|
|
533
|
+
// and keeps assertSatisfiableAuth's `sorobanCredentialsAddress` check exact.
|
|
534
|
+
let sim = await this.server.simulateTransaction(tx, undefined, undefined, false);
|
|
513
535
|
for (let round = 0; rpc.Api.isSimulationRestore(sim); round++) {
|
|
514
536
|
if (round >= 2) {
|
|
515
537
|
throw new HolderError(`${fn}: entries still need restoring after ${round} restore transactions — retry later`, contractId, fn);
|
|
516
538
|
}
|
|
517
539
|
await this.restore(sim, pub);
|
|
518
540
|
tx = build(await this.sourceAccount(pub, fn));
|
|
519
|
-
sim = await this.server.simulateTransaction(tx);
|
|
541
|
+
sim = await this.server.simulateTransaction(tx, undefined, undefined, false);
|
|
520
542
|
}
|
|
521
543
|
if (rpc.Api.isSimulationError(sim)) {
|
|
522
544
|
throw typedError(contractId, fn, sim.error, errNames);
|
|
523
545
|
}
|
|
524
546
|
const prepared = rpc.assembleTransaction(tx, sim).build();
|
|
525
547
|
this.assertSatisfiableAuth(prepared, pub, contractId, fn);
|
|
526
|
-
const txHash = prepared.hash()
|
|
548
|
+
const txHash = toHex(prepared.hash()); // (SDK17) hash() is Uint8Array
|
|
527
549
|
const signed = await this.signEnvelope(prepared.toXDR());
|
|
528
550
|
const envelope = TransactionBuilder.fromXDR(signed, this.passphrase);
|
|
529
551
|
let sent;
|
|
@@ -595,18 +617,18 @@ export class SoranHolder {
|
|
|
595
617
|
try {
|
|
596
618
|
const meta = got.resultMetaXdr;
|
|
597
619
|
const diags = got.diagnosticEventsXdr ??
|
|
598
|
-
(meta && meta.
|
|
599
|
-
? (meta.
|
|
600
|
-
: meta && meta.
|
|
601
|
-
? meta.
|
|
620
|
+
(meta && meta.type === "v3"
|
|
621
|
+
? (meta.value.sorobanMeta?.diagnosticEvents ?? [])
|
|
622
|
+
: meta && meta.type === "v4"
|
|
623
|
+
? meta.value.diagnosticEvents
|
|
602
624
|
: []);
|
|
603
625
|
outer: for (const d of diags) {
|
|
604
|
-
const body = d.event
|
|
605
|
-
for (const v of [...body.topics
|
|
606
|
-
if (v.
|
|
607
|
-
const err = v.error
|
|
608
|
-
if (err.
|
|
609
|
-
code = err.contractCode
|
|
626
|
+
const body = d.event.body.value;
|
|
627
|
+
for (const v of [...body.topics, body.data]) {
|
|
628
|
+
if (v.type === "scvError") {
|
|
629
|
+
const err = v.error;
|
|
630
|
+
if (err.type === "sceContract") {
|
|
631
|
+
code = err.contractCode;
|
|
610
632
|
break outer;
|
|
611
633
|
}
|
|
612
634
|
}
|
|
@@ -618,7 +640,7 @@ export class SoranHolder {
|
|
|
618
640
|
}
|
|
619
641
|
let resultCode = `tx status ${got.status}`;
|
|
620
642
|
try {
|
|
621
|
-
resultCode = got.resultXdr?.result
|
|
643
|
+
resultCode = got.resultXdr?.result.type ?? resultCode;
|
|
622
644
|
}
|
|
623
645
|
catch {
|
|
624
646
|
/* keep plain status */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sorandomains/holder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Manage your own Soran name on Stellar — records, profile, reverse, primary, and transfers, signed by your key.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"reverse-lookup"
|
|
40
40
|
],
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@stellar/stellar-sdk": ">=
|
|
42
|
+
"@stellar/stellar-sdk": ">=17 <18"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@stellar/stellar-sdk": "^
|
|
45
|
+
"@stellar/stellar-sdk": "^17.0.1",
|
|
46
46
|
"@types/node": "^22.20.1",
|
|
47
47
|
"esbuild": "^0.25.0",
|
|
48
48
|
"tsx": "^4.19.2",
|