@kronsdk/kron-sdk 0.4.0 → 0.6.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 +13 -4
- package/dist/index.d.ts +96 -9
- package/dist/index.js +154 -48
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -163,12 +163,24 @@ var ZERO_COVID = "00".repeat(32);
|
|
|
163
163
|
// src/native/spend.ts
|
|
164
164
|
var spend_exports = {};
|
|
165
165
|
__export(spend_exports, {
|
|
166
|
+
COVENANT_COMPUTE: () => COVENANT_COMPUTE,
|
|
167
|
+
COVENANT_DUST: () => COVENANT_DUST,
|
|
168
|
+
FUNDING_COMPUTE: () => FUNDING_COMPUTE,
|
|
169
|
+
TOKEN_COMPUTE: () => TOKEN_COMPUTE,
|
|
170
|
+
TX_VERSION: () => TX_VERSION,
|
|
166
171
|
assembleNativeTx: () => assembleNativeTx,
|
|
172
|
+
estimateNativeFee: () => estimateNativeFee,
|
|
167
173
|
signFundingInputs: () => signFundingInputs,
|
|
168
174
|
signPsktWithKey: () => signPsktWithKey,
|
|
169
175
|
toPsktJson: () => toPsktJson
|
|
170
176
|
});
|
|
177
|
+
var TX_VERSION = 1;
|
|
178
|
+
var FUNDING_COMPUTE = 10;
|
|
179
|
+
var TOKEN_COMPUTE = 500;
|
|
180
|
+
var COVENANT_COMPUTE = 2e3;
|
|
181
|
+
var COVENANT_DUST = 50000000n;
|
|
171
182
|
var SUBNET_ZERO = "0000000000000000000000000000000000000000";
|
|
183
|
+
var budgetForRole = (role) => role === "curve" || role === "pool" ? COVENANT_COMPUTE : TOKEN_COMPUTE;
|
|
172
184
|
function assembleNativeTx(k, opts) {
|
|
173
185
|
const { spend, fundingEntries, changeAddress, networkFee } = opts;
|
|
174
186
|
const kk = k;
|
|
@@ -178,6 +190,7 @@ function assembleNativeTx(k, opts) {
|
|
|
178
190
|
signatureScript: ci.signatureScript,
|
|
179
191
|
sequence: 0n,
|
|
180
192
|
sigOpCount: 0,
|
|
193
|
+
computeBudget: ci.computeBudget ?? budgetForRole(ci.role),
|
|
181
194
|
utxo: {
|
|
182
195
|
outpoint: { transactionId: ci.transactionId, index: ci.index },
|
|
183
196
|
amount: ci.value,
|
|
@@ -188,7 +201,7 @@ function assembleNativeTx(k, opts) {
|
|
|
188
201
|
})
|
|
189
202
|
);
|
|
190
203
|
const fundingInputs = fundingEntries.map(
|
|
191
|
-
(e) => new kk.TransactionInput({ previousOutpoint: e.outpoint, signatureScript: "", sequence: 0n, sigOpCount:
|
|
204
|
+
(e) => new kk.TransactionInput({ previousOutpoint: e.outpoint, signatureScript: "", sequence: 0n, sigOpCount: 0, computeBudget: FUNDING_COMPUTE, utxo: e })
|
|
192
205
|
);
|
|
193
206
|
const covInValue = spend.inputs.reduce((s, ci) => s + ci.value, 0n);
|
|
194
207
|
const fundingTotal = fundingEntries.reduce((s, e) => s + BigInt(e.amount), 0n);
|
|
@@ -196,10 +209,12 @@ function assembleNativeTx(k, opts) {
|
|
|
196
209
|
const covenantOut = spend.outputs.reduce((s, o) => s + o.value, 0n);
|
|
197
210
|
const change = totalIn - covenantOut - networkFee;
|
|
198
211
|
if (change < 0n) throw new Error(`insufficient funding: need ${covenantOut + networkFee} sompi, have ${totalIn}`);
|
|
199
|
-
const outputs = spend.outputs.map(
|
|
212
|
+
const outputs = spend.outputs.map(
|
|
213
|
+
(o) => o.binding ? new kk.TransactionOutput(o.value, o.scriptPublicKey, new kk.CovenantBinding(o.binding.authorizingInput, new kk.Hash(o.binding.covid))) : new kk.TransactionOutput(o.value, o.scriptPublicKey)
|
|
214
|
+
);
|
|
200
215
|
outputs.push(new kk.TransactionOutput(change, kk.payToAddressScript(changeAddress)));
|
|
201
216
|
const transaction = new kk.Transaction({
|
|
202
|
-
version:
|
|
217
|
+
version: TX_VERSION,
|
|
203
218
|
inputs: [...covInputs, ...fundingInputs],
|
|
204
219
|
outputs,
|
|
205
220
|
lockTime: 0n,
|
|
@@ -215,6 +230,27 @@ function assembleNativeTx(k, opts) {
|
|
|
215
230
|
change
|
|
216
231
|
};
|
|
217
232
|
}
|
|
233
|
+
function estimateNativeFee(k, networkId, asm, feeRateSompiPerGram) {
|
|
234
|
+
const kk = k;
|
|
235
|
+
const tx = asm.transaction;
|
|
236
|
+
const ins = tx.inputs;
|
|
237
|
+
const saved = asm.fundingInputIndexes.map((i) => ins[i].signatureScript);
|
|
238
|
+
for (const i of asm.fundingInputIndexes) ins[i].signatureScript = "00".repeat(66);
|
|
239
|
+
tx.inputs = ins;
|
|
240
|
+
let byteMass = 2000n;
|
|
241
|
+
try {
|
|
242
|
+
byteMass = BigInt(kk.calculateTransactionMass(networkId, tx));
|
|
243
|
+
} catch {
|
|
244
|
+
}
|
|
245
|
+
const ins2 = tx.inputs;
|
|
246
|
+
asm.fundingInputIndexes.forEach((i, j) => ins2[i].signatureScript = saved[j]);
|
|
247
|
+
tx.inputs = ins2;
|
|
248
|
+
let computeGrams = 0n;
|
|
249
|
+
for (const inp of tx.inputs) computeGrams += BigInt(inp.computeBudget || 0) * 100n;
|
|
250
|
+
const rate = BigInt(Math.max(Math.ceil(feeRateSompiPerGram), 1));
|
|
251
|
+
const fee = (byteMass + computeGrams) * rate * 3n / 2n;
|
|
252
|
+
return fee > 10000n ? fee : 10000n;
|
|
253
|
+
}
|
|
218
254
|
function signFundingInputs(k, tx, privKey, fundingInputIndexes) {
|
|
219
255
|
const inputs = tx.inputs;
|
|
220
256
|
for (const idx of fundingInputIndexes) {
|
|
@@ -247,7 +283,9 @@ var kcc20Tx_exports = {};
|
|
|
247
283
|
__export(kcc20Tx_exports, {
|
|
248
284
|
IDENTIFIER: () => IDENTIFIER,
|
|
249
285
|
addressPresenceOwned: () => addressPresenceOwned,
|
|
286
|
+
buildKcc20Send: () => buildKcc20Send,
|
|
250
287
|
covenantIdOwned: () => covenantIdOwned,
|
|
288
|
+
decodeKcc20Redeem: () => decodeKcc20Redeem,
|
|
251
289
|
kcc20Address: () => kcc20Address,
|
|
252
290
|
kcc20Spk: () => kcc20Spk,
|
|
253
291
|
kcc20SpkForState: () => kcc20SpkForState,
|
|
@@ -259,6 +297,7 @@ __export(kcc20Tx_exports, {
|
|
|
259
297
|
transferSigScript: () => transferSigScript
|
|
260
298
|
});
|
|
261
299
|
var IDENTIFIER = { PUBKEY: 0, SCRIPT_HASH: 1, COVENANT_ID: 2, ADDRESS: 3 };
|
|
300
|
+
var STATE_LEN = 46;
|
|
262
301
|
function materializeKcc20Script(tpl, state) {
|
|
263
302
|
const s = tpl.stateStart;
|
|
264
303
|
const t = tpl.script;
|
|
@@ -278,6 +317,25 @@ function materializeKcc20Script(tpl, state) {
|
|
|
278
317
|
out[s + 45] = state.isMinter ? 1 : 0;
|
|
279
318
|
return out;
|
|
280
319
|
}
|
|
320
|
+
function decodeKcc20Redeem(redeem, opts = {}) {
|
|
321
|
+
const hits = [];
|
|
322
|
+
for (let s2 = 0; s2 + STATE_LEN <= redeem.length; s2++) {
|
|
323
|
+
if (redeem[s2] === 32 && redeem[s2 + 33] === 1 && redeem[s2 + 34] <= 3 && redeem[s2 + 35] === 8 && redeem[s2 + 44] === 1 && redeem[s2 + 45] <= 1) hits.push(s2);
|
|
324
|
+
}
|
|
325
|
+
if (hits.length !== 1) throw new Error(`could not locate the kcc20 state region in the redeem script (${hits.length} candidate offsets) \u2014 is this a kcc20 token UTXO?`);
|
|
326
|
+
const s = hits[0];
|
|
327
|
+
let amount = 0n;
|
|
328
|
+
for (let i = 7; i >= 0; i--) amount = amount << 8n | BigInt(redeem[s + 36 + i]);
|
|
329
|
+
return {
|
|
330
|
+
template: { script: redeem.slice(), stateStart: s, maxIns: opts.maxIns ?? 4, maxOuts: opts.maxOuts ?? 4 },
|
|
331
|
+
state: {
|
|
332
|
+
ownerIdentifier: redeem.slice(s + 1, s + 33),
|
|
333
|
+
identifierType: redeem[s + 34],
|
|
334
|
+
amount,
|
|
335
|
+
isMinter: redeem[s + 45] === 1
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
}
|
|
281
339
|
var kcc20Spk = (k, redeem) => k.payToScriptHashScript(redeem);
|
|
282
340
|
var kcc20SpkForState = (k, tpl, state) => kcc20Spk(k, materializeKcc20Script(tpl, state));
|
|
283
341
|
function kcc20Address(k, tpl, state, network) {
|
|
@@ -327,6 +385,30 @@ function transferSigScript(k, redeem, newStates, witnesses, sigs = []) {
|
|
|
327
385
|
b.redeem(redeem);
|
|
328
386
|
return b.drain();
|
|
329
387
|
}
|
|
388
|
+
function buildKcc20Send(k, tpl, senderTokens, recipientPubkey32, sendAmount, presenceWitnessIdx, tokenCovid, opts = {}) {
|
|
389
|
+
if (senderTokens.length < 1) throw new Error("send requires at least one token UTXO");
|
|
390
|
+
if (!tokenCovid) throw new Error("send requires the token covenant id (indexer token info `covenantId`) for the output bindings");
|
|
391
|
+
const total = senderTokens.reduce((s, t) => s + t.state.amount, 0n);
|
|
392
|
+
const change = total - sendAmount;
|
|
393
|
+
if (sendAmount < 1n || change < 0n) throw new Error(`send requires 1 <= sendAmount <= ${total} (the selected UTXOs' total)`);
|
|
394
|
+
const dust = opts.tokenDust ?? 50000000n;
|
|
395
|
+
const owner = senderTokens[0].state.ownerIdentifier;
|
|
396
|
+
const recipientOut = addressPresenceOwned(recipientPubkey32, sendAmount);
|
|
397
|
+
const newStates = change >= 1n ? [recipientOut, addressPresenceOwned(owner, change)] : [recipientOut];
|
|
398
|
+
const witnesses = senderTokens.map(() => presenceWitnessIdx);
|
|
399
|
+
const inputs = senderTokens.map((t) => {
|
|
400
|
+
const r = materializeKcc20Script(tpl, t.state);
|
|
401
|
+
return { transactionId: t.transactionId, index: t.index, value: t.value, scriptPublicKey: kcc20Spk(k, r), signatureScript: transferSigScript(k, r, newStates, witnesses), redeem: r, role: "token" };
|
|
402
|
+
});
|
|
403
|
+
const binding = { covid: tokenCovid, authorizingInput: 0 };
|
|
404
|
+
const outputs = newStates.map((st, i) => ({
|
|
405
|
+
value: dust,
|
|
406
|
+
scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tpl, st)),
|
|
407
|
+
role: i === 0 ? "send" : "change",
|
|
408
|
+
binding
|
|
409
|
+
}));
|
|
410
|
+
return { kind: "transfer", inputs, outputs, economics: { sendAmount, change }, covids: { tokenCovid } };
|
|
411
|
+
}
|
|
330
412
|
|
|
331
413
|
// src/native/curveCpTx.ts
|
|
332
414
|
var curveCpTx_exports = {};
|
|
@@ -496,6 +578,9 @@ function buildAddLiquidity(k, tpl, tokenTpl, utxo, lpInventory, poolCovid, lpDep
|
|
|
496
578
|
if (lpDepositToken.state.amount !== q.dToken) throw new Error("LP deposit token UTXO must equal dToken exactly (split first)");
|
|
497
579
|
const dust = opts.tokenDust ?? 1000n;
|
|
498
580
|
const { kasReserve, tokenReserve, tokenCovid, lpCovid } = utxo.state;
|
|
581
|
+
const poolCovidHex = hexOf(poolCovid);
|
|
582
|
+
const tokenCovidHex = hexOf(tokenCovid);
|
|
583
|
+
const lpCovidHex = hexOf(lpCovid);
|
|
499
584
|
const poolTokenOut = covenantIdOwned(poolCovid, q.newToken, false);
|
|
500
585
|
const poolLpOut = covenantIdOwned(poolCovid, lpInventory.amount - q.dShares, false);
|
|
501
586
|
const lpSharesOut = addressPresenceOwned(lpPubkey, q.dShares);
|
|
@@ -515,17 +600,20 @@ function buildAddLiquidity(k, tpl, tokenTpl, utxo, lpInventory, poolCovid, lpDep
|
|
|
515
600
|
{ transactionId: lpInventory.transactionId, index: lpInventory.index, value: lpInventory.value, scriptPublicKey: kcc20Spk(k, poolLpInvRedeem), signatureScript: transferSigScript(k, poolLpInvRedeem, lStates, lWitnesses), redeem: poolLpInvRedeem, role: "poolLpInventory" }
|
|
516
601
|
];
|
|
517
602
|
const outputs = [
|
|
518
|
-
{ value: q.newKas * SCALE, scriptPublicKey: poolCpSpk(k, newRedeem), role: "pool" },
|
|
519
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken" },
|
|
520
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolLpOut)), role: "poolLpInventory" },
|
|
521
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, lpSharesOut)), role: "lpShares" }
|
|
603
|
+
{ value: q.newKas * SCALE, scriptPublicKey: poolCpSpk(k, newRedeem), role: "pool", binding: { covid: poolCovidHex, authorizingInput: 0 } },
|
|
604
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken", binding: { covid: tokenCovidHex, authorizingInput: 2 } },
|
|
605
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolLpOut)), role: "poolLpInventory", binding: { covid: lpCovidHex, authorizingInput: 3 } },
|
|
606
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, lpSharesOut)), role: "lpShares", binding: { covid: lpCovidHex, authorizingInput: 3 } }
|
|
522
607
|
];
|
|
523
|
-
return { kind: "addLiquidity", inputs, outputs, economics: { dKas: q.dKas, dToken: q.dToken, dShares: q.dShares, newShares: q.newShares }, covids: { poolCovid:
|
|
608
|
+
return { kind: "addLiquidity", inputs, outputs, economics: { dKas: q.dKas, dToken: q.dToken, dShares: q.dShares, newShares: q.newShares }, covids: { poolCovid: poolCovidHex, tokenCovid: tokenCovidHex } };
|
|
524
609
|
}
|
|
525
610
|
function buildRemoveLiquidity(k, tpl, tokenTpl, utxo, lpShares, poolCovid, lpPubkey, q, presenceWitnessIdx, opts = {}) {
|
|
526
611
|
if (lpShares.state.amount !== q.dShares) throw new Error("LP shares UTXO must equal dShares exactly (split first)");
|
|
527
612
|
const dust = opts.tokenDust ?? 1000n;
|
|
528
613
|
const { kasReserve, tokenReserve, tokenCovid, lpCovid } = utxo.state;
|
|
614
|
+
const poolCovidHex = hexOf(poolCovid);
|
|
615
|
+
const tokenCovidHex = hexOf(tokenCovid);
|
|
616
|
+
const lpCovidHex = hexOf(lpCovid);
|
|
529
617
|
const poolTokenOut = covenantIdOwned(poolCovid, q.newToken, false);
|
|
530
618
|
const lpTokenOut = addressPresenceOwned(lpPubkey, q.dToken);
|
|
531
619
|
const poolLpOut = covenantIdOwned(poolCovid, q.dShares, false);
|
|
@@ -543,12 +631,12 @@ function buildRemoveLiquidity(k, tpl, tokenTpl, utxo, lpShares, poolCovid, lpPub
|
|
|
543
631
|
{ transactionId: lpShares.transactionId, index: lpShares.index, value: lpShares.value, scriptPublicKey: kcc20Spk(k, lpSharesRedeem), signatureScript: transferSigScript(k, lpSharesRedeem, lStates, lWitnesses), redeem: lpSharesRedeem, role: "lpShares" }
|
|
544
632
|
];
|
|
545
633
|
const outputs = [
|
|
546
|
-
{ value: q.newKas * SCALE, scriptPublicKey: poolCpSpk(k, newRedeem), role: "pool" },
|
|
547
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken" },
|
|
548
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, lpTokenOut)), role: "lpToken" },
|
|
549
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolLpOut)), role: "poolLpInventory" }
|
|
634
|
+
{ value: q.newKas * SCALE, scriptPublicKey: poolCpSpk(k, newRedeem), role: "pool", binding: { covid: poolCovidHex, authorizingInput: 0 } },
|
|
635
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
636
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, lpTokenOut)), role: "lpToken", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
637
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolLpOut)), role: "poolLpInventory", binding: { covid: lpCovidHex, authorizingInput: 2 } }
|
|
550
638
|
];
|
|
551
|
-
return { kind: "removeLiquidity", inputs, outputs, economics: { dShares: q.dShares, dKas: q.dKas, dToken: q.dToken, newShares: q.newShares }, covids: { poolCovid:
|
|
639
|
+
return { kind: "removeLiquidity", inputs, outputs, economics: { dShares: q.dShares, dKas: q.dKas, dToken: q.dToken, newShares: q.newShares }, covids: { poolCovid: poolCovidHex, tokenCovid: tokenCovidHex } };
|
|
552
640
|
}
|
|
553
641
|
function buildBindLp(k, tpl, tokenTpl, utxo, poolCovid, lockedShares, opts = {}) {
|
|
554
642
|
if (utxo.state.lpCovid.length !== 32 || !utxo.state.lpCovid.every((b2) => b2 === 0)) throw new Error("pool lpCovid is already bound \u2014 bindLp is one-time");
|
|
@@ -576,12 +664,13 @@ function buildBindLp(k, tpl, tokenTpl, utxo, poolCovid, lockedShares, opts = {})
|
|
|
576
664
|
const inputs = [
|
|
577
665
|
{ transactionId: utxo.transactionId, index: utxo.index, value: poolValue, scriptPublicKey: poolCpSpk(k, curRedeem), signatureScript: bindSig, redeem: curRedeem, role: "pool" }
|
|
578
666
|
];
|
|
667
|
+
const poolCovidHex = hexOf(poolCovid);
|
|
579
668
|
const outputs = [
|
|
580
|
-
{ value: poolValue, scriptPublicKey: poolCpSpk(k, boundRedeem), role: "pool" },
|
|
581
|
-
{ value: dust, scriptPublicKey: floorSpk, role: "lpFloor" },
|
|
582
|
-
{ value: dust, scriptPublicKey: invSpk, role: "lpInventory" }
|
|
669
|
+
{ value: poolValue, scriptPublicKey: poolCpSpk(k, boundRedeem), role: "pool", binding: { covid: poolCovidHex, authorizingInput: 0 } },
|
|
670
|
+
{ value: dust, scriptPublicKey: floorSpk, role: "lpFloor", binding: { covid: lpCovidHex, authorizingInput: 0 } },
|
|
671
|
+
{ value: dust, scriptPublicKey: invSpk, role: "lpInventory", binding: { covid: lpCovidHex, authorizingInput: 0 } }
|
|
583
672
|
];
|
|
584
|
-
return { kind: "bindLp", inputs, outputs, economics: { lockedShares, inventoryAmount }, covids: { poolCovid:
|
|
673
|
+
return { kind: "bindLp", inputs, outputs, economics: { lockedShares, inventoryAmount }, covids: { poolCovid: poolCovidHex, tokenCovid: hexOf(tokenCovid) }, lpCovidHex, lpInventoryAmount: inventoryAmount };
|
|
585
674
|
}
|
|
586
675
|
|
|
587
676
|
// src/native/curveCpTx.ts
|
|
@@ -639,6 +728,8 @@ function buildCpBuy(k, tpl, tokenTpl, utxo, inventory, curveCovid, buyerPubkey,
|
|
|
639
728
|
if (tokenOut <= 0n || tokenOut >= inventory.amount) throw new Error("invalid tokenOut");
|
|
640
729
|
if (inventory.amount !== utxo.state.tokenReserve) throw new Error("inventory.amount must equal the curve's committed tokenReserve");
|
|
641
730
|
const dust = opts.tokenDust ?? 1000n;
|
|
731
|
+
const curveCovidHex = hexOf2(curveCovid);
|
|
732
|
+
const tokenCovidHex = hexOf2(utxo.state.tokenCovid);
|
|
642
733
|
const newKas = utxo.realKas + kasIn;
|
|
643
734
|
if (newKas > MAX_KAS) throw new Error("buy exceeds the curve max raise (9,000,000 TKAS)");
|
|
644
735
|
const newToken = inventory.amount - tokenOut;
|
|
@@ -664,13 +755,13 @@ function buildCpBuy(k, tpl, tokenTpl, utxo, inventory, curveCovid, buyerPubkey,
|
|
|
664
755
|
})
|
|
665
756
|
];
|
|
666
757
|
const outputs = [
|
|
667
|
-
{ value: newKas, scriptPublicKey: cpSpk(k, newCurveRedeem), role: "curve" },
|
|
668
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, invOutRedeem), role: "inventory" },
|
|
669
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, buyerRedeem), role: "recipient" },
|
|
758
|
+
{ value: newKas, scriptPublicKey: cpSpk(k, newCurveRedeem), role: "curve", binding: { covid: curveCovidHex, authorizingInput: 0 } },
|
|
759
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, invOutRedeem), role: "inventory", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
760
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, buyerRedeem), role: "recipient", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
670
761
|
{ value: padFee3(creatorFee), scriptPublicKey: p2pkSpk(k, tpl.params.creatorFeeOwner), role: "creatorFee" },
|
|
671
762
|
{ value: padFee3(platformFee), scriptPublicKey: p2pkSpk(k, tpl.params.platformFeeOwner), role: "platformFee" }
|
|
672
763
|
];
|
|
673
|
-
return { kind: "buy", inputs, outputs, economics: { kasIn, tokenOut, creatorFee, platformFee, newRealKas: newKas, newTokenReserve: newToken, merged: mergeSum }, covids: { tokenCovid:
|
|
764
|
+
return { kind: "buy", inputs, outputs, economics: { kasIn, tokenOut, creatorFee, platformFee, newRealKas: newKas, newTokenReserve: newToken, merged: mergeSum }, covids: { tokenCovid: tokenCovidHex } };
|
|
674
765
|
}
|
|
675
766
|
function buildCpSell(k, tpl, tokenTpl, utxo, sellerTokens, inventory, curveCovid, traderPubkey, tokenIn, kasOut, presenceWitnessIdx, opts = {}) {
|
|
676
767
|
if (utxo.state.graduated) throw new Error("curve has graduated \u2014 sells are locked");
|
|
@@ -679,6 +770,8 @@ function buildCpSell(k, tpl, tokenTpl, utxo, sellerTokens, inventory, curveCovid
|
|
|
679
770
|
if (kasOut <= 0n || kasOut % SCALE2 !== 0n || kasOut > utxo.realKas) throw new Error("invalid kasOut");
|
|
680
771
|
if (inventory.amount !== utxo.state.tokenReserve) throw new Error("inventory.amount must equal the curve's committed tokenReserve");
|
|
681
772
|
const dust = opts.tokenDust ?? 1000n;
|
|
773
|
+
const curveCovidHex = hexOf2(curveCovid);
|
|
774
|
+
const tokenCovidHex = hexOf2(utxo.state.tokenCovid);
|
|
682
775
|
const sellerIn = sellerTokens.reduce((s, t) => s + t.state.amount, 0n);
|
|
683
776
|
const change = sellerIn - tokenIn;
|
|
684
777
|
if (change < 0n) throw new Error("seller inputs are less than the sell amount");
|
|
@@ -703,13 +796,13 @@ function buildCpSell(k, tpl, tokenTpl, utxo, sellerTokens, inventory, curveCovid
|
|
|
703
796
|
})
|
|
704
797
|
];
|
|
705
798
|
const outputs = [
|
|
706
|
-
{ value: utxo.realKas - kasOut, scriptPublicKey: cpSpk(k, newCurveRedeem), role: "curve" },
|
|
707
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, invOutRedeem), role: "inventory" },
|
|
799
|
+
{ value: utxo.realKas - kasOut, scriptPublicKey: cpSpk(k, newCurveRedeem), role: "curve", binding: { covid: curveCovidHex, authorizingInput: 0 } },
|
|
800
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, invOutRedeem), role: "inventory", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
708
801
|
{ value: padFee3(creatorFee), scriptPublicKey: p2pkSpk(k, tpl.params.creatorFeeOwner), role: "creatorFee" },
|
|
709
802
|
{ value: padFee3(platformFee), scriptPublicKey: p2pkSpk(k, tpl.params.platformFeeOwner), role: "platformFee" }
|
|
710
803
|
];
|
|
711
|
-
if (hasChange) outputs.push({ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, traderChangeOut)), role: "seller" });
|
|
712
|
-
return { kind: "sell", inputs, outputs, economics: { tokenIn, kasOut, change, creatorFee, platformFee, newRealKas: utxo.realKas - kasOut, newTokenReserve: newToken }, covids: { tokenCovid:
|
|
804
|
+
if (hasChange) outputs.push({ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, traderChangeOut)), role: "seller", binding: { covid: tokenCovidHex, authorizingInput: 1 } });
|
|
805
|
+
return { kind: "sell", inputs, outputs, economics: { tokenIn, kasOut, change, creatorFee, platformFee, newRealKas: utxo.realKas - kasOut, newTokenReserve: newToken }, covids: { tokenCovid: tokenCovidHex } };
|
|
713
806
|
}
|
|
714
807
|
function buildCpGraduate(k, tpl, tokenTpl, poolTemplate, utxo, inventory, curveCovid, poolLockedShares, opts = {}) {
|
|
715
808
|
if (utxo.state.graduated) throw new Error("already graduated");
|
|
@@ -740,10 +833,12 @@ function buildCpGraduate(k, tpl, tokenTpl, poolTemplate, utxo, inventory, curveC
|
|
|
740
833
|
{ transactionId: utxo.transactionId, index: utxo.index, value: utxo.realKas, scriptPublicKey: cpSpk(k, curRedeem), signatureScript: graduateSigV2(k, curRedeem, poolState, poolTokens), redeem: curRedeem, role: "curve" },
|
|
741
834
|
{ transactionId: inventory.transactionId, index: inventory.index, value: inventory.value, scriptPublicKey: kcc20Spk(k, invRedeem), signatureScript: transferSigScript(k, invRedeem, [poolTokens], [0]), redeem: invRedeem, role: "inventory" }
|
|
742
835
|
];
|
|
836
|
+
const curveCovidHex = hexOf2(curveCovid);
|
|
837
|
+
const tokenCovidHex = hexOf2(A);
|
|
743
838
|
const outputs = [
|
|
744
|
-
{ value: lockedValue, scriptPublicKey: cpSpk(k, lockedRedeem), role: "curve" },
|
|
745
|
-
{ value: poolKas, scriptPublicKey: poolSpkV, role: "pool" },
|
|
746
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, poolTokenRedeem), role: "poolToken" },
|
|
839
|
+
{ value: lockedValue, scriptPublicKey: cpSpk(k, lockedRedeem), role: "curve", binding: { covid: curveCovidHex, authorizingInput: 0 } },
|
|
840
|
+
{ value: poolKas, scriptPublicKey: poolSpkV, role: "pool", binding: { covid: poolCovidHex, authorizingInput: 0 } },
|
|
841
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, poolTokenRedeem), role: "poolToken", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
747
842
|
{ value: padFee3(gradFee), scriptPublicKey: p2pkSpk(k, tpl.params.platformFeeOwner), role: "gradFee" }
|
|
748
843
|
];
|
|
749
844
|
return { kind: "graduate", inputs, outputs, economics: { poolKas, gradFee, leftover, poolLockedShares }, covids: { tokenCovid: hexOf2(A), poolCovid: poolCovidHex } };
|
|
@@ -756,14 +851,15 @@ function buildSplitToken(k, tokenTpl, sellerToken, sellAmount, presenceWitnessId
|
|
|
756
851
|
const out1 = addressPresenceOwned(owner, sellAmount);
|
|
757
852
|
const out2 = addressPresenceOwned(owner, change);
|
|
758
853
|
const redeem = materializeKcc20Script(tokenTpl, sellerToken.state);
|
|
854
|
+
const binding = opts.tokenCovid ? { covid: opts.tokenCovid, authorizingInput: 0 } : void 0;
|
|
759
855
|
const inputs = [
|
|
760
856
|
{ transactionId: sellerToken.transactionId, index: sellerToken.index, value: sellerToken.value, scriptPublicKey: kcc20Spk(k, redeem), signatureScript: transferSigScript(k, redeem, [out1, out2], [presenceWitnessIdx]), redeem, role: "sellerToken" }
|
|
761
857
|
];
|
|
762
858
|
const outputs = [
|
|
763
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, out1)), role: "split" },
|
|
764
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, out2)), role: "change" }
|
|
859
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, out1)), role: "split", binding },
|
|
860
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, out2)), role: "change", binding }
|
|
765
861
|
];
|
|
766
|
-
return { kind: "sell", inputs, outputs, economics: { sellAmount, change }, covids: { tokenCovid:
|
|
862
|
+
return { kind: "sell", inputs, outputs, economics: { sellAmount, change }, covids: opts.tokenCovid ? { tokenCovid: opts.tokenCovid } : {} };
|
|
767
863
|
}
|
|
768
864
|
function buildConsolidate(k, tokenTpl, tokens, presenceWitnessIdx, opts = {}) {
|
|
769
865
|
if (tokens.length < 2) throw new Error("consolidate needs at least 2 UTXOs");
|
|
@@ -777,10 +873,11 @@ function buildConsolidate(k, tokenTpl, tokens, presenceWitnessIdx, opts = {}) {
|
|
|
777
873
|
const r = materializeKcc20Script(tokenTpl, t.state);
|
|
778
874
|
return { transactionId: t.transactionId, index: t.index, value: t.value, scriptPublicKey: kcc20Spk(k, r), signatureScript: transferSigScript(k, r, newStates, witnesses), redeem: r, role: "token" };
|
|
779
875
|
});
|
|
876
|
+
const binding = opts.tokenCovid ? { covid: opts.tokenCovid, authorizingInput: 0 } : void 0;
|
|
780
877
|
const outputs = [
|
|
781
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, merged)), role: "merged" }
|
|
878
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, merged)), role: "merged", binding }
|
|
782
879
|
];
|
|
783
|
-
return { kind: "sell", inputs, outputs, economics: { total }, covids: { tokenCovid:
|
|
880
|
+
return { kind: "sell", inputs, outputs, economics: { total }, covids: opts.tokenCovid ? { tokenCovid: opts.tokenCovid } : {} };
|
|
784
881
|
}
|
|
785
882
|
var hexOf2 = (u8) => Array.from(u8, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
786
883
|
|
|
@@ -825,6 +922,8 @@ function v3SwapSellSig(k, redeem, kasOutUnits, poolTokenOut, traderChangeOut) {
|
|
|
825
922
|
function buildPoolV3SwapKasForToken(k, tpl, tokenTpl, params, utxo, poolCovid, traderPubkey, q, mergeTokens = [], presenceWitnessIdx = 0, opts = {}) {
|
|
826
923
|
const dust = opts.tokenDust ?? 1000n;
|
|
827
924
|
const { kasReserve, tokenReserve, tokenCovid, totalShares, lpCovid } = utxo.state;
|
|
925
|
+
const poolCovidHex = hexOf3(poolCovid);
|
|
926
|
+
const tokenCovidHex = hexOf3(tokenCovid);
|
|
828
927
|
const mergeSum = mergeTokens.reduce((s, t) => s + t.state.amount, 0n);
|
|
829
928
|
const poolTokenOut = covenantIdOwned(poolCovid, q.newToken, false);
|
|
830
929
|
const traderTokenOut = addressPresenceOwned(traderPubkey, q.tokenOut + mergeSum);
|
|
@@ -842,18 +941,20 @@ function buildPoolV3SwapKasForToken(k, tpl, tokenTpl, params, utxo, poolCovid, t
|
|
|
842
941
|
})
|
|
843
942
|
];
|
|
844
943
|
const outputs = [
|
|
845
|
-
{ value: q.newKas * SCALE, scriptPublicKey: poolCpV3Spk(k, newRedeem), role: "pool" },
|
|
846
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken" },
|
|
847
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, traderTokenOut)), role: "trader" },
|
|
944
|
+
{ value: q.newKas * SCALE, scriptPublicKey: poolCpV3Spk(k, newRedeem), role: "pool", binding: { covid: poolCovidHex, authorizingInput: 0 } },
|
|
945
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
946
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, traderTokenOut)), role: "trader", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
848
947
|
{ value: q.creatorOut, scriptPublicKey: p2pkSpk2(k, params.creatorFeeOwner), role: "creatorFee" },
|
|
849
948
|
{ value: q.platformOut, scriptPublicKey: p2pkSpk2(k, params.platformFeeOwner), role: "platformFee" }
|
|
850
949
|
];
|
|
851
|
-
return { kind: "swapKasForToken", inputs, outputs, economics: { kasIn: q.kasIn, tokenOut: q.tokenOut }, covids: { poolCovid:
|
|
950
|
+
return { kind: "swapKasForToken", inputs, outputs, economics: { kasIn: q.kasIn, tokenOut: q.tokenOut }, covids: { poolCovid: poolCovidHex, tokenCovid: tokenCovidHex } };
|
|
852
951
|
}
|
|
853
952
|
function buildPoolV3SwapTokenForKas(k, tpl, tokenTpl, params, utxo, poolCovid, traderPubkey, traderTokens, q, presenceWitnessIdx, opts = {}) {
|
|
854
953
|
if (traderTokens.length < 1) throw new Error("need at least one trader token");
|
|
855
954
|
const dust = opts.tokenDust ?? 1000n;
|
|
856
955
|
const { kasReserve, tokenReserve, tokenCovid, totalShares, lpCovid } = utxo.state;
|
|
956
|
+
const poolCovidHex = hexOf3(poolCovid);
|
|
957
|
+
const tokenCovidHex = hexOf3(tokenCovid);
|
|
857
958
|
const traderIn = traderTokens.reduce((s, t) => s + t.state.amount, 0n);
|
|
858
959
|
const change = traderIn - q.tokenIn;
|
|
859
960
|
if (change < 0n) throw new Error("trader inputs are less than the sell amount");
|
|
@@ -874,13 +975,13 @@ function buildPoolV3SwapTokenForKas(k, tpl, tokenTpl, params, utxo, poolCovid, t
|
|
|
874
975
|
})
|
|
875
976
|
];
|
|
876
977
|
const outputs = [
|
|
877
|
-
{ value: q.newKas * SCALE, scriptPublicKey: poolCpV3Spk(k, newRedeem), role: "pool" },
|
|
878
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken" },
|
|
978
|
+
{ value: q.newKas * SCALE, scriptPublicKey: poolCpV3Spk(k, newRedeem), role: "pool", binding: { covid: poolCovidHex, authorizingInput: 0 } },
|
|
979
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, poolTokenOut)), role: "poolToken", binding: { covid: tokenCovidHex, authorizingInput: 1 } },
|
|
879
980
|
{ value: q.creatorOut, scriptPublicKey: p2pkSpk2(k, params.creatorFeeOwner), role: "creatorFee" },
|
|
880
981
|
{ value: q.platformOut, scriptPublicKey: p2pkSpk2(k, params.platformFeeOwner), role: "platformFee" }
|
|
881
982
|
];
|
|
882
|
-
if (hasChange) outputs.push({ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, traderChangeOut)), role: "trader" });
|
|
883
|
-
return { kind: "swapTokenForKas", inputs, outputs, economics: { kasOut: q.kasOut, tokenIn: q.tokenIn }, covids: { poolCovid:
|
|
983
|
+
if (hasChange) outputs.push({ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, traderChangeOut)), role: "trader", binding: { covid: tokenCovidHex, authorizingInput: 1 } });
|
|
984
|
+
return { kind: "swapTokenForKas", inputs, outputs, economics: { kasOut: q.kasOut, tokenIn: q.tokenIn }, covids: { poolCovid: poolCovidHex, tokenCovid: tokenCovidHex } };
|
|
884
985
|
}
|
|
885
986
|
|
|
886
987
|
// src/native/vestingTx.ts
|
|
@@ -895,6 +996,7 @@ __export(vestingTx_exports, {
|
|
|
895
996
|
vestingSpkForState: () => vestingSpkForState
|
|
896
997
|
});
|
|
897
998
|
var VEST_SELECTOR = { claim: 0, claimFinal: 1 };
|
|
999
|
+
var hexOf4 = (u8) => Array.from(u8, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
898
1000
|
function vestedAmount(total, startScore, durationScore, daaScore) {
|
|
899
1001
|
if (daaScore <= startScore) return 0n;
|
|
900
1002
|
const elapsed = BigInt(daaScore - startScore);
|
|
@@ -920,6 +1022,8 @@ function buildVestingClaim(k, vestTpl, tokenTpl, vestingUtxo, lockedToken, vesti
|
|
|
920
1022
|
const remaining = total - claimed;
|
|
921
1023
|
if (release <= 0n || release >= remaining) throw new Error("partial claim must be > 0 and < remaining (use claimFinal to drain)");
|
|
922
1024
|
const dust = opts.tokenDust ?? 1000n;
|
|
1025
|
+
const vestingCovidHex = hexOf4(vestingCovid);
|
|
1026
|
+
const tokenBinding = opts.tokenCovid ? { covid: opts.tokenCovid, authorizingInput: 1 } : void 0;
|
|
923
1027
|
const newClaimed = claimed + release, newRemaining = remaining - release;
|
|
924
1028
|
const curRedeem = materializeVestingScript(vestTpl, claimed);
|
|
925
1029
|
const newRedeem = materializeVestingScript(vestTpl, newClaimed);
|
|
@@ -936,20 +1040,22 @@ function buildVestingClaim(k, vestTpl, tokenTpl, vestingUtxo, lockedToken, vesti
|
|
|
936
1040
|
{ transactionId: lockedToken.transactionId, index: lockedToken.index, value: lockedToken.value, scriptPublicKey: kcc20Spk(k, lockedRedeem), signatureScript: transferSigScript(k, lockedRedeem, [relockState, recipientState], [0]), redeem: lockedRedeem, role: "lockedToken" }
|
|
937
1041
|
];
|
|
938
1042
|
const outputs = [
|
|
939
|
-
{ value: vestingUtxo.value, scriptPublicKey: vestingSpk(k, newRedeem), role: "vesting" },
|
|
1043
|
+
{ value: vestingUtxo.value, scriptPublicKey: vestingSpk(k, newRedeem), role: "vesting", binding: { covid: vestingCovidHex, authorizingInput: 0 } },
|
|
940
1044
|
// V continuation (claimed bumped)
|
|
941
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, relockState)), role: "relock" },
|
|
1045
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, relockState)), role: "relock", binding: tokenBinding },
|
|
942
1046
|
// re-locked (A, V-owned)
|
|
943
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, recipientState)), role: "recipient" }
|
|
1047
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, recipientState)), role: "recipient", binding: tokenBinding }
|
|
944
1048
|
// to creator (A, presence)
|
|
945
1049
|
];
|
|
946
|
-
return { kind: "claim", inputs, outputs, economics: { release, newClaimed } };
|
|
1050
|
+
return { kind: "claim", inputs, outputs, economics: { release, newClaimed }, covids: opts.tokenCovid ? { tokenCovid: opts.tokenCovid } : {} };
|
|
947
1051
|
}
|
|
948
1052
|
function buildVestingClaimFinal(k, vestTpl, tokenTpl, vestingUtxo, lockedToken, vestingCovid, creatorPubkey, claimed, opts = {}) {
|
|
949
1053
|
const total = BigInt(vestTpl.params.total);
|
|
950
1054
|
if (claimed < 0n || claimed >= total) throw new Error("nothing left to claim");
|
|
951
1055
|
const remaining = total - claimed;
|
|
952
1056
|
const dust = opts.tokenDust ?? 1000n;
|
|
1057
|
+
const vestingCovidHex = hexOf4(vestingCovid);
|
|
1058
|
+
const tokenBinding = opts.tokenCovid ? { covid: opts.tokenCovid, authorizingInput: 1 } : void 0;
|
|
953
1059
|
const curRedeem = materializeVestingScript(vestTpl, claimed);
|
|
954
1060
|
const newRedeem = materializeVestingScript(vestTpl, total);
|
|
955
1061
|
const lockedState = covenantIdOwned(vestingCovid, remaining, false);
|
|
@@ -963,10 +1069,10 @@ function buildVestingClaimFinal(k, vestTpl, tokenTpl, vestingUtxo, lockedToken,
|
|
|
963
1069
|
{ transactionId: lockedToken.transactionId, index: lockedToken.index, value: lockedToken.value, scriptPublicKey: kcc20Spk(k, lockedRedeem), signatureScript: transferSigScript(k, lockedRedeem, [recipientState], [0]), redeem: lockedRedeem, role: "lockedToken" }
|
|
964
1070
|
];
|
|
965
1071
|
const outputs = [
|
|
966
|
-
{ value: vestingUtxo.value, scriptPublicKey: vestingSpk(k, newRedeem), role: "vesting" },
|
|
967
|
-
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, recipientState)), role: "recipient" }
|
|
1072
|
+
{ value: vestingUtxo.value, scriptPublicKey: vestingSpk(k, newRedeem), role: "vesting", binding: { covid: vestingCovidHex, authorizingInput: 0 } },
|
|
1073
|
+
{ value: dust, scriptPublicKey: kcc20Spk(k, materializeKcc20Script(tokenTpl, recipientState)), role: "recipient", binding: tokenBinding }
|
|
968
1074
|
];
|
|
969
|
-
return { kind: "claimFinal", inputs, outputs, economics: { release: remaining } };
|
|
1075
|
+
return { kind: "claimFinal", inputs, outputs, economics: { release: remaining }, covids: opts.tokenCovid ? { tokenCovid: opts.tokenCovid } : {} };
|
|
970
1076
|
}
|
|
971
1077
|
|
|
972
1078
|
// src/wallet/index.ts
|