@empereur-rouge/pms-sdk 0.3.8 → 0.5.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/dist/index.cjs +287 -101
- package/dist/index.d.cts +394 -123
- package/dist/index.d.ts +394 -123
- package/dist/index.js +279 -100
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,14 +20,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
DAY_MS: () => DAY_MS,
|
|
23
24
|
PmsClient: () => PmsClient,
|
|
24
25
|
PmsWallet: () => PmsWallet,
|
|
25
26
|
decryptPayload: () => decryptPayload,
|
|
27
|
+
effectiveValue: () => effectiveValue,
|
|
26
28
|
formatAmount: () => formatAmount,
|
|
27
29
|
fromHex: () => fromHex,
|
|
30
|
+
hashlockHash: () => hashlockHash,
|
|
28
31
|
isValidMnemonic: () => isValidMnemonic,
|
|
32
|
+
makeUnlock: () => makeUnlock,
|
|
33
|
+
multisigAddress: () => multisigAddress,
|
|
29
34
|
parseAmount: () => parseAmount,
|
|
30
|
-
|
|
35
|
+
spendableUtxos: () => spendableUtxos,
|
|
36
|
+
toHex: () => toHex,
|
|
37
|
+
txSigningMessage: () => txSigningMessage
|
|
31
38
|
});
|
|
32
39
|
module.exports = __toCommonJS(index_exports);
|
|
33
40
|
|
|
@@ -42,6 +49,7 @@ var import_english = require("@scure/bip39/wordlists/english");
|
|
|
42
49
|
// src/utils.ts
|
|
43
50
|
var import_sha2 = require("@noble/hashes/sha2");
|
|
44
51
|
var import_utils = require("@noble/hashes/utils");
|
|
52
|
+
var import_base = require("@scure/base");
|
|
45
53
|
function sha256Hash(data) {
|
|
46
54
|
return (0, import_sha2.sha256)(data);
|
|
47
55
|
}
|
|
@@ -54,12 +62,103 @@ function fromHex(hex) {
|
|
|
54
62
|
function encodeUtf8(str) {
|
|
55
63
|
return new TextEncoder().encode(str);
|
|
56
64
|
}
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
65
|
+
function toBase64(bytes) {
|
|
66
|
+
return import_base.base64.encode(bytes);
|
|
67
|
+
}
|
|
68
|
+
function txSigningMessage(networkId, inputs, outputs, fee) {
|
|
69
|
+
const canonInputs = inputs.map((i) => ({
|
|
70
|
+
out: { txid: i.out.txid, index: i.out.index }
|
|
71
|
+
}));
|
|
72
|
+
const canonOutputs = outputs.map((o) => {
|
|
73
|
+
const out = {
|
|
74
|
+
address: o.address,
|
|
75
|
+
amount: o.amount
|
|
76
|
+
};
|
|
77
|
+
if (o.asset_id !== void 0 && o.asset_id !== null) {
|
|
78
|
+
out.asset_id = o.asset_id;
|
|
79
|
+
}
|
|
80
|
+
if (o.locked_until !== void 0 && o.locked_until !== null) {
|
|
81
|
+
out.locked_until = o.locked_until;
|
|
82
|
+
}
|
|
83
|
+
if (o.spend_condition !== void 0 && o.spend_condition !== null) {
|
|
84
|
+
out.spend_condition = o.spend_condition;
|
|
85
|
+
}
|
|
86
|
+
if (o.created_at !== void 0 && o.created_at !== null) {
|
|
87
|
+
out.created_at = o.created_at;
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
});
|
|
91
|
+
const canon = {
|
|
92
|
+
network_id: networkId,
|
|
93
|
+
inputs: canonInputs,
|
|
94
|
+
outputs: canonOutputs,
|
|
95
|
+
fee
|
|
96
|
+
};
|
|
97
|
+
return toHex(sha256Hash(encodeUtf8(JSON.stringify(canon))));
|
|
98
|
+
}
|
|
99
|
+
var PLAIN_VARIANT_TO_PAYLOAD_TYPE = {
|
|
100
|
+
Genesis: "Genesis",
|
|
101
|
+
Mint: "Mint",
|
|
102
|
+
TxUtxo: "Transaction",
|
|
103
|
+
Milestone: "Milestone",
|
|
104
|
+
Nft: "Nft",
|
|
105
|
+
ConfigUpdate: "ConfigUpdate",
|
|
106
|
+
Reward: "Reward",
|
|
107
|
+
EncryptedReward: "EncryptedReward",
|
|
108
|
+
TokenCreate: "TokenCreate",
|
|
109
|
+
BridgeLock: "BridgeLock",
|
|
110
|
+
BridgeMint: "BridgeMint",
|
|
111
|
+
Freeze: "Freeze",
|
|
112
|
+
Unfreeze: "Unfreeze",
|
|
113
|
+
Seize: "Seize",
|
|
114
|
+
Reverse: "Reverse",
|
|
115
|
+
ContractRegister: "ContractRegister",
|
|
116
|
+
ContractUpdate: "ContractUpdate",
|
|
117
|
+
LedgerOwnershipTransfer: "LedgerOwnershipTransfer",
|
|
118
|
+
CoordinatorKeyRotate: "CoordinatorKeyRotate"
|
|
119
|
+
};
|
|
120
|
+
var EMPTY_COMMITMENT = "0000000000000000000000000000000000000000000000000000000000000000";
|
|
121
|
+
function computeBlockId(parents, payload, nonce) {
|
|
122
|
+
let payload_type;
|
|
123
|
+
let commitment;
|
|
124
|
+
let len_hint;
|
|
125
|
+
let key_version;
|
|
126
|
+
if (payload === void 0 || payload === null) {
|
|
127
|
+
payload_type = "None";
|
|
128
|
+
commitment = EMPTY_COMMITMENT;
|
|
129
|
+
len_hint = 0;
|
|
130
|
+
key_version = 0;
|
|
131
|
+
} else if ("Plain" in payload) {
|
|
132
|
+
const plain = payload.Plain;
|
|
133
|
+
const variant = typeof plain === "string" ? plain : Object.keys(plain)[0];
|
|
134
|
+
payload_type = PLAIN_VARIANT_TO_PAYLOAD_TYPE[variant] ?? variant;
|
|
135
|
+
const plainBytes = encodeUtf8(JSON.stringify(plain));
|
|
136
|
+
commitment = toHex(sha256Hash(plainBytes));
|
|
137
|
+
len_hint = plainBytes.length;
|
|
138
|
+
key_version = 0;
|
|
139
|
+
} else {
|
|
140
|
+
const enc = payload.Encrypted;
|
|
141
|
+
payload_type = "Encrypted";
|
|
142
|
+
commitment = enc.commitment;
|
|
143
|
+
len_hint = enc.ciphertext_b64.length;
|
|
144
|
+
key_version = enc.key_version;
|
|
145
|
+
}
|
|
146
|
+
const head = {
|
|
147
|
+
parents,
|
|
148
|
+
nonce,
|
|
149
|
+
envelope: { payload_type, commitment, len_hint, key_version }
|
|
150
|
+
};
|
|
151
|
+
return toHex(sha256Hash(encodeUtf8(JSON.stringify(head))));
|
|
152
|
+
}
|
|
153
|
+
function x25519FromAddress(address) {
|
|
154
|
+
try {
|
|
155
|
+
const decoded = import_base.bech32m.decode(address, false);
|
|
156
|
+
const bytes = import_base.bech32m.fromWords(decoded.words);
|
|
157
|
+
if (bytes.length !== 52) return void 0;
|
|
158
|
+
return toHex(bytes.slice(20));
|
|
159
|
+
} catch {
|
|
160
|
+
return void 0;
|
|
161
|
+
}
|
|
63
162
|
}
|
|
64
163
|
function parseAmount(amount) {
|
|
65
164
|
const [whole, frac = ""] = amount.split(".");
|
|
@@ -72,6 +171,47 @@ function formatAmount(sats) {
|
|
|
72
171
|
const fracStr = frac.toString().padStart(8, "0");
|
|
73
172
|
return `${whole}.${fracStr}`;
|
|
74
173
|
}
|
|
174
|
+
var DAY_MS = 864e5;
|
|
175
|
+
function multisigAddress(m, pubkeys) {
|
|
176
|
+
const normalized = pubkeys.map((pk) => {
|
|
177
|
+
const t = pk.trim();
|
|
178
|
+
return (t.startsWith("0x") ? t.slice(2) : t).toLowerCase();
|
|
179
|
+
}).sort();
|
|
180
|
+
const parts = [
|
|
181
|
+
encodeUtf8("pms-multisig-v1"),
|
|
182
|
+
new Uint8Array([m, normalized.length]),
|
|
183
|
+
...normalized.map((pk) => encodeUtf8(pk))
|
|
184
|
+
];
|
|
185
|
+
const total = parts.reduce((n, p) => n + p.length, 0);
|
|
186
|
+
const buf = new Uint8Array(total);
|
|
187
|
+
let off = 0;
|
|
188
|
+
for (const p of parts) {
|
|
189
|
+
buf.set(p, off);
|
|
190
|
+
off += p.length;
|
|
191
|
+
}
|
|
192
|
+
return `msig1${toHex(sha256Hash(buf).slice(0, 20))}`;
|
|
193
|
+
}
|
|
194
|
+
function hashlockHash(preimage) {
|
|
195
|
+
const bytes = typeof preimage === "string" ? encodeUtf8(preimage) : preimage;
|
|
196
|
+
return toHex(sha256Hash(bytes));
|
|
197
|
+
}
|
|
198
|
+
function effectiveValue(amount, createdAtMs, nowMs, bpsPerDay) {
|
|
199
|
+
if (createdAtMs === void 0 || createdAtMs === null || !bpsPerDay) {
|
|
200
|
+
return amount;
|
|
201
|
+
}
|
|
202
|
+
const elapsed = nowMs - createdAtMs;
|
|
203
|
+
const days = elapsed > 0 ? BigInt(Math.floor(elapsed / DAY_MS)) : 0n;
|
|
204
|
+
if (days === 0n) return amount;
|
|
205
|
+
const sats = parseAmount(amount);
|
|
206
|
+
const scaled = sats * 10000n - sats * BigInt(bpsPerDay) * days;
|
|
207
|
+
if (scaled <= 0n) return "0.00000000";
|
|
208
|
+
return formatAmount(scaled / 10000n);
|
|
209
|
+
}
|
|
210
|
+
function spendableUtxos(utxos, nowMs = Date.now()) {
|
|
211
|
+
return utxos.filter(
|
|
212
|
+
(u) => u.locked_until === void 0 || u.locked_until === null || u.locked_until <= nowMs
|
|
213
|
+
);
|
|
214
|
+
}
|
|
75
215
|
|
|
76
216
|
// src/wallet.ts
|
|
77
217
|
var PmsWallet = class _PmsWallet {
|
|
@@ -246,11 +386,33 @@ var PmsWallet = class _PmsWallet {
|
|
|
246
386
|
function isValidMnemonic(mnemonic) {
|
|
247
387
|
return (0, import_bip39.validateMnemonic)(mnemonic.trim().toLowerCase(), import_english.wordlist);
|
|
248
388
|
}
|
|
389
|
+
function makeUnlock(signers, txHashHex, opts) {
|
|
390
|
+
if (signers.length === 0) {
|
|
391
|
+
throw new Error("makeUnlock: at least one signer is required");
|
|
392
|
+
}
|
|
393
|
+
const msg = encodeUtf8(txHashHex);
|
|
394
|
+
const sign = (w) => toBase64(fromHex(w.sign(msg)));
|
|
395
|
+
const [primary, ...rest] = signers;
|
|
396
|
+
const unlock = {
|
|
397
|
+
pubkey_hex: primary.publicKeyHex,
|
|
398
|
+
signature_b64: sign(primary)
|
|
399
|
+
};
|
|
400
|
+
if (rest.length > 0) {
|
|
401
|
+
unlock.cosigners = rest.map((w) => ({
|
|
402
|
+
pubkey_hex: w.publicKeyHex,
|
|
403
|
+
signature_b64: sign(w)
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
if (opts?.preimageHex !== void 0) {
|
|
407
|
+
unlock.preimage_hex = opts.preimageHex;
|
|
408
|
+
}
|
|
409
|
+
return unlock;
|
|
410
|
+
}
|
|
249
411
|
|
|
250
412
|
// src/types.ts
|
|
251
413
|
var DEFAULT_CONFIG = {
|
|
252
414
|
networkId: "pms-mainnet",
|
|
253
|
-
protocolVersion:
|
|
415
|
+
protocolVersion: 3,
|
|
254
416
|
timeout: 3e4,
|
|
255
417
|
seedNodes: [],
|
|
256
418
|
enableRacing: true,
|
|
@@ -265,13 +427,13 @@ var import_aes = require("@noble/ciphers/aes.js");
|
|
|
265
427
|
var import_hkdf2 = require("@noble/hashes/hkdf");
|
|
266
428
|
var import_sha23 = require("@noble/hashes/sha2");
|
|
267
429
|
var import_utils3 = require("@noble/hashes/utils");
|
|
268
|
-
var
|
|
430
|
+
var import_base2 = require("@scure/base");
|
|
269
431
|
var SCHEME = "x25519+aes256gcm";
|
|
270
432
|
var HKDF_SALT = new TextEncoder().encode("pms-dek-wrap");
|
|
271
433
|
var HKDF_INFO_KEK = new TextEncoder().encode("kek-v1");
|
|
272
434
|
var HKDF_INFO_KID = new TextEncoder().encode("kid-v1");
|
|
273
435
|
function fromBase64(str) {
|
|
274
|
-
return
|
|
436
|
+
return import_base2.base64.decode(str);
|
|
275
437
|
}
|
|
276
438
|
function sha256Hex(data) {
|
|
277
439
|
return (0, import_utils3.bytesToHex)((0, import_sha23.sha256)(data));
|
|
@@ -436,11 +598,24 @@ var PmsClient = class {
|
|
|
436
598
|
}
|
|
437
599
|
/**
|
|
438
600
|
* Récupère les UTXOs d'une adresse.
|
|
601
|
+
*
|
|
602
|
+
* Depuis dag-pms v0.10.0, chaque UTXO expose aussi ses contraintes de
|
|
603
|
+
* dépense : `locked_until` (time-lock), `spend_condition`
|
|
604
|
+
* (MultiSig/HashLock) et `created_at` (base du demurrage). Utiliser
|
|
605
|
+
* [`spendableUtxos`] pour exclure les UTXOs encore verrouillés avant
|
|
606
|
+
* toute sélection de coins côté client.
|
|
439
607
|
*/
|
|
440
608
|
async getUtxos(address) {
|
|
441
609
|
const res = await this.fetch(`/v1/wallet/${address}/utxos`, void 0, { idempotent: true });
|
|
442
610
|
return res.utxos ?? [];
|
|
443
611
|
}
|
|
612
|
+
/**
|
|
613
|
+
* Dernier snapshot de preuve de réserves ancré (protocole 2.6,
|
|
614
|
+
* `GET /v1/reserves/latest`). 404 si aucun snapshot n'a encore été ancré.
|
|
615
|
+
*/
|
|
616
|
+
async getLatestReserves() {
|
|
617
|
+
return this.fetch("/v1/reserves/latest", void 0, { idempotent: true });
|
|
618
|
+
}
|
|
444
619
|
// ═══════════════════════════════════════════════════════════════════════
|
|
445
620
|
// Wallet API (Custodial — Server-Side)
|
|
446
621
|
// ═══════════════════════════════════════════════════════════════════════
|
|
@@ -897,101 +1072,83 @@ var PmsClient = class {
|
|
|
897
1072
|
}
|
|
898
1073
|
/**
|
|
899
1074
|
* Envoie des tokens à une adresse.
|
|
900
|
-
*
|
|
1075
|
+
*
|
|
1076
|
+
* Flux aligné sur dag-pms v0.9.0 (single-writer + vérification des
|
|
1077
|
+
* signatures de transaction par l'engine) :
|
|
1078
|
+
* 1. `POST /v1/tx/prepare` — le serveur sélectionne les UTXOs et calcule
|
|
1079
|
+
* les frais.
|
|
1080
|
+
* 2. Vérification défensive côté client : l'output destinataire demandé
|
|
1081
|
+
* existe bien, et le `tx_hash` retourné correspond au message canonique
|
|
1082
|
+
* recalculé localement (`txSigningMessage`). On ne signe JAMAIS un hash
|
|
1083
|
+
* opaque non vérifié.
|
|
1084
|
+
* 3. Le wallet signe la TRANSACTION (unlocks) — pas le bloc. C'est le
|
|
1085
|
+
* serveur qui forge et signe le bloc (single-writer enforcement).
|
|
1086
|
+
* 4. `POST /v1/wallet/tx/send` avec la TX signée + les clés X25519 des
|
|
1087
|
+
* destinataires pour le chiffrement du payload.
|
|
1088
|
+
*
|
|
1089
|
+
* @param params.to - Adresse destinataire (Bech32m de préférence)
|
|
1090
|
+
* @param params.amount - Montant décimal (ex: "10.0")
|
|
1091
|
+
* @param params.wallet - Wallet signataire (propriétaire des UTXOs)
|
|
1092
|
+
* @param params.assetId - Asset ID optionnel (undefined = PMS natif)
|
|
1093
|
+
* @returns `{id, status, block_id}` — id du bloc forgé par le serveur
|
|
901
1094
|
*/
|
|
902
1095
|
async send(params) {
|
|
903
|
-
const { to, amount, wallet,
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
const amountSats = parseAmount(amount);
|
|
912
|
-
const variableFee = amountSats * feeRateBps / 10000n;
|
|
913
|
-
const fee = baseFeeSats + variableFee;
|
|
914
|
-
const totalNeeded = amountSats + fee;
|
|
915
|
-
let selectedSats = 0n;
|
|
916
|
-
const selectedUtxos = [];
|
|
917
|
-
for (const utxo of utxos) {
|
|
918
|
-
selectedUtxos.push(utxo);
|
|
919
|
-
selectedSats += parseAmount(utxo.amount || "0");
|
|
920
|
-
if (selectedSats >= totalNeeded) break;
|
|
1096
|
+
const { to, amount, wallet, assetId } = params;
|
|
1097
|
+
const prepareBody = {
|
|
1098
|
+
from: wallet.address,
|
|
1099
|
+
to,
|
|
1100
|
+
amount
|
|
1101
|
+
};
|
|
1102
|
+
if (assetId !== void 0) {
|
|
1103
|
+
prepareBody.asset_id = assetId;
|
|
921
1104
|
}
|
|
922
|
-
|
|
1105
|
+
const prepared = await this.prepareTx(prepareBody);
|
|
1106
|
+
const { unsigned_tx, tx_hash } = prepared;
|
|
1107
|
+
const requestedSats = parseAmount(amount);
|
|
1108
|
+
const recipientOutput = unsigned_tx.outputs.find(
|
|
1109
|
+
(o) => o.address === to && (o.asset_id ?? void 0) === (assetId ?? void 0) && parseAmount(o.amount) >= requestedSats
|
|
1110
|
+
);
|
|
1111
|
+
if (!recipientOutput) {
|
|
923
1112
|
throw new Error(
|
|
924
|
-
`
|
|
1113
|
+
`Prepared transaction does not contain the requested output (to=${to}, amount=${amount}, asset=${assetId ?? "PMS"}). Refusing to sign a transaction that does not pay the intended recipient.`
|
|
925
1114
|
);
|
|
926
1115
|
}
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
if (change > 0n) {
|
|
938
|
-
outputs.push({ address: wallet.address, amount: formatAmount(change) });
|
|
1116
|
+
const localHash = txSigningMessage(
|
|
1117
|
+
this.config.networkId,
|
|
1118
|
+
unsigned_tx.inputs,
|
|
1119
|
+
unsigned_tx.outputs,
|
|
1120
|
+
unsigned_tx.fee
|
|
1121
|
+
);
|
|
1122
|
+
if (localHash !== tx_hash) {
|
|
1123
|
+
throw new Error(
|
|
1124
|
+
`tx_hash mismatch: server returned ${tx_hash}, locally computed ${localHash}. Either the client networkId ("${this.config.networkId}") does not match the node's network, or the server response was tampered with. Refusing to sign.`
|
|
1125
|
+
);
|
|
939
1126
|
}
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
index: utxo.outpoint.index
|
|
944
|
-
}
|
|
945
|
-
}));
|
|
946
|
-
const txCanonical = {
|
|
947
|
-
inputs,
|
|
948
|
-
outputs,
|
|
949
|
-
fee: formatAmount(fee)
|
|
950
|
-
};
|
|
951
|
-
const txMessage = JSON.stringify(txCanonical);
|
|
952
|
-
const txSignatureHex = wallet.sign(encodeUtf8(txMessage));
|
|
953
|
-
const txSigBytes = fromHex(txSignatureHex);
|
|
954
|
-
const txSigB64 = btoa(String.fromCharCode(...txSigBytes));
|
|
955
|
-
const unlocks = inputs.map(() => ({
|
|
1127
|
+
const sigHex = wallet.sign(encodeUtf8(tx_hash));
|
|
1128
|
+
const sigB64 = toBase64(fromHex(sigHex));
|
|
1129
|
+
const unlocks = unsigned_tx.inputs.map(() => ({
|
|
956
1130
|
pubkey_hex: wallet.publicKeyHex,
|
|
957
|
-
signature_b64:
|
|
1131
|
+
signature_b64: sigB64
|
|
958
1132
|
}));
|
|
959
1133
|
const tx = {
|
|
960
|
-
inputs,
|
|
961
|
-
outputs,
|
|
962
|
-
fee:
|
|
1134
|
+
inputs: unsigned_tx.inputs,
|
|
1135
|
+
outputs: unsigned_tx.outputs,
|
|
1136
|
+
fee: unsigned_tx.fee,
|
|
963
1137
|
unlocks
|
|
964
1138
|
};
|
|
965
|
-
const
|
|
966
|
-
const
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
signer_pk_hex: wallet.publicKeyHex
|
|
979
|
-
};
|
|
980
|
-
const messageToSign = JSON.stringify(canonicalView);
|
|
981
|
-
const signatureHex = wallet.sign(encodeUtf8(messageToSign));
|
|
982
|
-
const signatureBytes = fromHex(signatureHex);
|
|
983
|
-
const signatureB64 = btoa(String.fromCharCode(...signatureBytes));
|
|
984
|
-
const wireBlock = {
|
|
985
|
-
id: blockId,
|
|
986
|
-
parents,
|
|
987
|
-
payload_json: payloadJson,
|
|
988
|
-
nonce,
|
|
989
|
-
network_id: this.config.networkId,
|
|
990
|
-
protocol_version: this.config.protocolVersion,
|
|
991
|
-
signer_pk_hex: wallet.publicKeyHex,
|
|
992
|
-
signature_hex: signatureB64
|
|
993
|
-
};
|
|
994
|
-
return this.submitBlock(wireBlock);
|
|
1139
|
+
const recipientsXpk = [wallet.x25519PublicKeyHex];
|
|
1140
|
+
const toXpk = x25519FromAddress(to);
|
|
1141
|
+
if (toXpk && !recipientsXpk.includes(toXpk)) {
|
|
1142
|
+
recipientsXpk.push(toXpk);
|
|
1143
|
+
}
|
|
1144
|
+
const resp = await this.fetch(
|
|
1145
|
+
"/v1/wallet/tx/send",
|
|
1146
|
+
{
|
|
1147
|
+
method: "POST",
|
|
1148
|
+
body: JSON.stringify({ tx, recipients_xpk: recipientsXpk })
|
|
1149
|
+
}
|
|
1150
|
+
);
|
|
1151
|
+
return { ...resp, block_id: resp.id };
|
|
995
1152
|
}
|
|
996
1153
|
// ═══════════════════════════════════════════════════════════════════════
|
|
997
1154
|
// Méthodes NFT Cube (Burn et Mint spécialisé)
|
|
@@ -999,7 +1156,15 @@ var PmsClient = class {
|
|
|
999
1156
|
/**
|
|
1000
1157
|
* Transférer un NFT à un autre propriétaire.
|
|
1001
1158
|
* Prend en charge le re-chiffrement des métadonnées via le coordinateur.
|
|
1002
|
-
*
|
|
1159
|
+
*
|
|
1160
|
+
* @deprecated Cette méthode soumet un WireBlock signé par la clé
|
|
1161
|
+
* utilisateur via `/submit/block`. Depuis dag-pms v0.9.0, l'engine tourne
|
|
1162
|
+
* en mode **single-writer** : tout bloc signé par une clé non-coordinateur
|
|
1163
|
+
* est rejeté. Cette méthode ne fonctionne que sur un réseau SANS
|
|
1164
|
+
* single-writer enforcement. Utilisez les flux server-side
|
|
1165
|
+
* (`/v1/nft/transfer/prepare` + endpoints serveur) qui forgent et signent
|
|
1166
|
+
* le bloc côté coordinateur.
|
|
1167
|
+
*
|
|
1003
1168
|
* @param params - Paramètres du transfert
|
|
1004
1169
|
* @param params.tokenId - Identifiant du NFT
|
|
1005
1170
|
* @param params.to - Adresse du nouveau propriétaire
|
|
@@ -1035,7 +1200,7 @@ var PmsClient = class {
|
|
|
1035
1200
|
const payload = { Plain: { Nft: action } };
|
|
1036
1201
|
const payloadJson = JSON.stringify(payload);
|
|
1037
1202
|
const nonce = 0;
|
|
1038
|
-
const blockId = computeBlockId(parents,
|
|
1203
|
+
const blockId = computeBlockId(parents, payload, nonce);
|
|
1039
1204
|
const canonicalView = {
|
|
1040
1205
|
id: blockId,
|
|
1041
1206
|
parents,
|
|
@@ -1067,10 +1232,17 @@ var PmsClient = class {
|
|
|
1067
1232
|
* Seul le propriétaire du NFT peut le brûler.
|
|
1068
1233
|
* Une fois brûlé, le NFT est supprimé définitivement.
|
|
1069
1234
|
*
|
|
1070
|
-
* Pour les Cubes authentiques (avec signature Authority valide),
|
|
1235
|
+
* Pour les Cubes authentiques (avec signature Authority valide),
|
|
1071
1236
|
* un remboursement est calculé selon la formule:
|
|
1072
1237
|
* `(weight * size * density) / 10000` PMS
|
|
1073
|
-
*
|
|
1238
|
+
*
|
|
1239
|
+
* @deprecated Cette méthode poste un WireBlock signé par la clé
|
|
1240
|
+
* utilisateur. Depuis dag-pms v0.9.0, l'engine tourne en mode
|
|
1241
|
+
* **single-writer** : tout bloc signé par une clé non-coordinateur est
|
|
1242
|
+
* rejeté. Cette méthode ne fonctionne que sur un réseau SANS single-writer
|
|
1243
|
+
* enforcement. Le flux supporté est le burn server-side
|
|
1244
|
+
* (`/v1/nft/burn-simple`), où le serveur forge et signe le bloc.
|
|
1245
|
+
*
|
|
1074
1246
|
* @param params - Paramètres du burn
|
|
1075
1247
|
* @param params.tokenId - Identifiant du NFT à brûler
|
|
1076
1248
|
* @param params.wallet - Wallet PMS du propriétaire (doit être l'owner actuel)
|
|
@@ -1104,7 +1276,7 @@ var PmsClient = class {
|
|
|
1104
1276
|
};
|
|
1105
1277
|
const payloadJson = JSON.stringify(payload);
|
|
1106
1278
|
const nonce = 0;
|
|
1107
|
-
const blockId = computeBlockId(parents,
|
|
1279
|
+
const blockId = computeBlockId(parents, payload, nonce);
|
|
1108
1280
|
const canonicalView = {
|
|
1109
1281
|
id: blockId,
|
|
1110
1282
|
parents,
|
|
@@ -1136,7 +1308,14 @@ var PmsClient = class {
|
|
|
1136
1308
|
}
|
|
1137
1309
|
/**
|
|
1138
1310
|
* Brûle (détruit) plusieurs NFTs en une seule transaction.
|
|
1139
|
-
*
|
|
1311
|
+
*
|
|
1312
|
+
* @deprecated Cette méthode poste un WireBlock signé par la clé
|
|
1313
|
+
* utilisateur. Depuis dag-pms v0.9.0, l'engine tourne en mode
|
|
1314
|
+
* **single-writer** : tout bloc signé par une clé non-coordinateur est
|
|
1315
|
+
* rejeté. Cette méthode ne fonctionne que sur un réseau SANS single-writer
|
|
1316
|
+
* enforcement. Le flux supporté est le burn server-side
|
|
1317
|
+
* (`/v1/nft/burn-simple`), où le serveur forge et signe le bloc.
|
|
1318
|
+
*
|
|
1140
1319
|
* @param params - Paramètres du batch burn
|
|
1141
1320
|
* @param params.tokenIds - Liste des Identifiants des NFTs à brûler
|
|
1142
1321
|
* @param params.wallet - Wallet PMS du propriétaire
|
|
@@ -1161,7 +1340,7 @@ var PmsClient = class {
|
|
|
1161
1340
|
};
|
|
1162
1341
|
const payloadJson = JSON.stringify(payload);
|
|
1163
1342
|
const nonce = 0;
|
|
1164
|
-
const blockId = computeBlockId(parents,
|
|
1343
|
+
const blockId = computeBlockId(parents, payload, nonce);
|
|
1165
1344
|
const canonicalView = {
|
|
1166
1345
|
id: blockId,
|
|
1167
1346
|
parents,
|
|
@@ -1430,12 +1609,19 @@ function mergeAbortSignals(a, b) {
|
|
|
1430
1609
|
}
|
|
1431
1610
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1432
1611
|
0 && (module.exports = {
|
|
1612
|
+
DAY_MS,
|
|
1433
1613
|
PmsClient,
|
|
1434
1614
|
PmsWallet,
|
|
1435
1615
|
decryptPayload,
|
|
1616
|
+
effectiveValue,
|
|
1436
1617
|
formatAmount,
|
|
1437
1618
|
fromHex,
|
|
1619
|
+
hashlockHash,
|
|
1438
1620
|
isValidMnemonic,
|
|
1621
|
+
makeUnlock,
|
|
1622
|
+
multisigAddress,
|
|
1439
1623
|
parseAmount,
|
|
1440
|
-
|
|
1624
|
+
spendableUtxos,
|
|
1625
|
+
toHex,
|
|
1626
|
+
txSigningMessage
|
|
1441
1627
|
});
|