@kaspacom/kcc20-tx-builder 0.8.0-fee.12 → 0.8.0-fee.14
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/CHANGELOG.md +4 -0
- package/dist/cjs/engine.js +152 -93
- package/dist/cjs/engine.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +152 -93
- package/dist/engine.js.map +1 -1
- package/docs/COMPATIBILITY.json +1 -1
- package/package.json +1 -1
- package/src/engine.ts +146 -95
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0-fee.13
|
|
4
|
+
|
|
5
|
+
- Accept the indexer ownerScheme alias in seller-sweep bid inputs after checking it agrees with owner_scheme; preserve strict runtime state and script checks.
|
|
6
|
+
|
|
3
7
|
## 0.8.0-fee.12 (unreleased)
|
|
4
8
|
|
|
5
9
|
- Build imported Argent fee-market wrap/unwrap and profile-aware trades with the corrected V2 wrapper.
|
package/dist/cjs/engine.js
CHANGED
|
@@ -4175,15 +4175,18 @@ function createKcc20PsktBuilderEngine(options) {
|
|
|
4175
4175
|
String(utxo.state.wrapper_spk_hash).toLowerCase() !== holderPlan.wrapper.scriptHash) {
|
|
4176
4176
|
throw new Error(`bid ${slot} differs from fixed market policy`);
|
|
4177
4177
|
}
|
|
4178
|
-
// The indexer adds policy
|
|
4178
|
+
// The indexer adds policy summaries and an ownerScheme alias. They are not
|
|
4179
4179
|
// part of the on-chain bid state and must not enter script reconstruction.
|
|
4180
|
-
const { creatorFeeBps: indexedCreatorFeeBps, feePolicyVersion: indexedFeePolicyVersion, ...bidState } = utxo.state;
|
|
4180
|
+
const { creatorFeeBps: indexedCreatorFeeBps, feePolicyVersion: indexedFeePolicyVersion, ownerScheme: indexedOwnerScheme, ...bidState } = utxo.state;
|
|
4181
4181
|
if ((indexedCreatorFeeBps !== undefined &&
|
|
4182
4182
|
Number(indexedCreatorFeeBps) !== params.feePolicy.creatorFeeBps) ||
|
|
4183
4183
|
(indexedFeePolicyVersion !== undefined &&
|
|
4184
4184
|
Number(indexedFeePolicyVersion) !== params.feePolicy.version)) {
|
|
4185
4185
|
throw new Error(`bid ${slot} indexed policy summary differs from fixed policy`);
|
|
4186
4186
|
}
|
|
4187
|
+
if (indexedOwnerScheme !== undefined && indexedOwnerScheme !== scheme) {
|
|
4188
|
+
throw new Error(`bid ${slot} indexed owner scheme differs from contract state`);
|
|
4189
|
+
}
|
|
4187
4190
|
const bidScript = (0, escrow_market_artifacts_js_1.buildKcc20FeeMarketRoleScript)({ artifact: artifacts.bid,
|
|
4188
4191
|
role: "bid", state: bidState });
|
|
4189
4192
|
const buyerPlan = (0, escrow_market_setup_js_1.prepareKcc20FeeMarketWrappedHolder)({ ...base,
|
|
@@ -4326,99 +4329,155 @@ function createKcc20PsktBuilderEngine(options) {
|
|
|
4326
4329
|
? outputSompi + priorityFee - covenantSompi + 10000n
|
|
4327
4330
|
: priorityFee + 10000n;
|
|
4328
4331
|
const fundingEntry = (0, sale_common_js_1.selectFundingEntry)(walletUtxos.entries, fundingNeeded, spentEntries.map(entry => entry.outpoint), params.fundingOutpoint);
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
const
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
indexes
|
|
4364
|
-
|
|
4332
|
+
let estimatedFundingFeeSompi = priorityFee;
|
|
4333
|
+
const buildWithFunding = (fundingEntry) => {
|
|
4334
|
+
const fundingChange = covenantSompi + (0, sale_common_js_1.utxoAmountSompi)(fundingEntry) - outputSompi - priorityFee;
|
|
4335
|
+
if (fundingChange <= 10000n)
|
|
4336
|
+
throw new Error("seller group funding change is too small");
|
|
4337
|
+
const fundingChangeIndex = outputs.length;
|
|
4338
|
+
const candidateOutputs = [...outputs,
|
|
4339
|
+
new TransactionOutput(fundingChange, payToAddressScript(walletAddress))];
|
|
4340
|
+
const transaction = new Transaction({ version: 1, lockTime: 0n,
|
|
4341
|
+
inputs: [
|
|
4342
|
+
{ previousOutpoint: holderEntry.outpoint, utxo: holderEntry,
|
|
4343
|
+
sequence: 0n, sigOpCount: 0, computeBudget: 1000 },
|
|
4344
|
+
...bidEntries.map(({ entry }) => ({ previousOutpoint: entry.outpoint, utxo: entry,
|
|
4345
|
+
sequence: 0n, sigOpCount: 0, computeBudget: 100 })),
|
|
4346
|
+
...(ticketEntry ? [{ previousOutpoint: ticketEntry.outpoint, utxo: ticketEntry,
|
|
4347
|
+
sequence: 0n, sigOpCount: 0, computeBudget: 600 }] : []),
|
|
4348
|
+
{ previousOutpoint: fundingEntry.outpoint, utxo: fundingEntry,
|
|
4349
|
+
sequence: 0n, sigOpCount: 0, computeBudget: 30 },
|
|
4350
|
+
], outputs: candidateOutputs, subnetworkId: sale_common_js_1.SUBNETWORK_ID_NATIVE, gas: 0n, payload: "",
|
|
4351
|
+
});
|
|
4352
|
+
// Pinned signed consensus proof uses 394 units for ten-bid leader and
|
|
4353
|
+
// 43 for each bid delegator. Leave more than 2x headroom per role.
|
|
4354
|
+
(0, sale_common_js_1.setVersionOneInputMassFields)(transaction, 1000);
|
|
4355
|
+
for (let slot = 0; slot < legs.length; slot++)
|
|
4356
|
+
transaction.inputs[slot + 1].computeBudget = 100;
|
|
4357
|
+
const ticketInputIndex = ticketEntry ? legs.length + 1 : -1;
|
|
4358
|
+
if (ticketEntry)
|
|
4359
|
+
transaction.inputs[ticketInputIndex].computeBudget = 600;
|
|
4360
|
+
const fundingInputIndex = legs.length + 1 + (ticketEntry ? 1 : 0);
|
|
4361
|
+
transaction.inputs[fundingInputIndex].computeBudget = 30;
|
|
4362
|
+
assertUniqueTransactionInputOutpoints(transaction, "fee-market seller group");
|
|
4363
|
+
const legBytes = new Uint8Array(legs.length * 32);
|
|
4364
|
+
const view = new DataView(legBytes.buffer);
|
|
4365
|
+
for (let slot = 0; slot < legs.length; slot++) {
|
|
4366
|
+
const indexes = legIndexes[slot];
|
|
4367
|
+
for (const [field, value] of [legs[slot].fill, indexes.buyerIndex,
|
|
4368
|
+
indexes.continuationIndex < 0 ? 0 : indexes.continuationIndex,
|
|
4369
|
+
indexes.sellerIndex].entries()) {
|
|
4370
|
+
view.setBigInt64(slot * 32 + field * 8, BigInt(value), true);
|
|
4371
|
+
}
|
|
4365
4372
|
}
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
delegate.
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4373
|
+
const receiptParts = templateParts((0, abi_js_1.normalizeSilverScriptArtifact)(artifacts.receipt));
|
|
4374
|
+
const scripts = [{ inputIndex: 0,
|
|
4375
|
+
scriptHex: (0, sale_common_js_1.bytesToHex)(holderPlan.holder.redeemScript), signType: 1,
|
|
4376
|
+
signatureScript: { mode: "ordered-args", args: [
|
|
4377
|
+
{ type: "signature" }, i64TemplateArg(legs.length), dataTemplateArg(legBytes),
|
|
4378
|
+
dataTemplateArg(vector), i64TemplateArg(ticketInputIndex), i64TemplateArg(receiptOutputIndex),
|
|
4379
|
+
i64TemplateArg(changeIndex), i64TemplateArg(refundIndex), i64TemplateArg(ticketRefundIndex),
|
|
4380
|
+
dataTemplateArg(feeTotal > 0n ? receiptParts.prefix : new Uint8Array()),
|
|
4381
|
+
dataTemplateArg(feeTotal > 0n ? receiptParts.suffix : new Uint8Array()),
|
|
4382
|
+
dataTemplateArg((0, abi_js_1.dispatchTagFor)(artifacts.holder, "sellIntoBids")),
|
|
4383
|
+
] } }];
|
|
4384
|
+
if (ticketEntry)
|
|
4385
|
+
scripts.push(feeTicketBurnScriptHint(ticketInputIndex, ticket.script, ticket.burnDispatchTag, ticketRefundIndex, ticket.burnTakesRefundOutput));
|
|
4386
|
+
for (let slot = 0; slot < legs.length; slot++) {
|
|
4387
|
+
const delegate = covenantScriptBuilder(kw);
|
|
4388
|
+
for (const value of [0, slot, legs[slot].remaining,
|
|
4389
|
+
legIndexes[slot].continuationIndex])
|
|
4390
|
+
delegate.addI64(BigInt(value));
|
|
4391
|
+
delegate.addData((0, abi_js_1.dispatchTagFor)(artifacts.bid, "delegateSellerGroup"));
|
|
4392
|
+
transaction.inputs[slot + 1].signatureScript = encodeCovenantP2shSignatureScript(delegate.drain(), legs[slot].bidScript.redeemScript);
|
|
4393
|
+
}
|
|
4394
|
+
const feeResult = transactionWithPredictedSignedFeeChange(kw, transaction, fundingChangeIndex, network, "fee-market seller group", candidate => {
|
|
4395
|
+
const serialized = candidate.serializeToSafeJSON();
|
|
4396
|
+
if (typeof serialized !== "string")
|
|
4397
|
+
throw new Error("seller group preflight serialization failed");
|
|
4398
|
+
const predicted = transactionJsonWithScriptHints(kw, JSON.parse(serialized), scripts);
|
|
4399
|
+
predicted.inputs[fundingInputIndex].signatureScript = encodeP2pkSignatureScript((0, sale_common_js_1.bytesToHex)(dummySignatureBytes()));
|
|
4400
|
+
return typeof kw.Transaction.deserializeFromSafeJSON === "function"
|
|
4401
|
+
? kw.Transaction.deserializeFromSafeJSON(JSON.stringify(predicted))
|
|
4402
|
+
: kw.Transaction.deserializeFromJSON(JSON.stringify(predicted));
|
|
4403
|
+
});
|
|
4404
|
+
estimatedFundingFeeSompi = feeResult.requiredFeeSompi;
|
|
4405
|
+
const signedMass = calculateToccataV1NonContextualMass(feeResult.predictedTransaction, "fee-market seller group");
|
|
4406
|
+
const storageMass = calculateToccataStorageMass(feeResult.predictedTransaction, "fee-market seller group");
|
|
4407
|
+
if (signedMass.computeMass > CONSOLIDATION_TARGET_TRANSACTION_MASS ||
|
|
4408
|
+
signedMass.transientMass > CONSOLIDATION_TARGET_TRANSACTION_MASS * 2n ||
|
|
4409
|
+
storageMass > CONSOLIDATION_TARGET_TRANSACTION_MASS) {
|
|
4410
|
+
throw (0, sale_common_js_1.kcc20PsktBuilderError)("fee-market seller group exceeds signed mass target", "TRANSACTION_MASS_EXCEEDED", { computeMass: signedMass.computeMass,
|
|
4411
|
+
transientMass: signedMass.transientMass, storageMass });
|
|
4412
|
+
}
|
|
4413
|
+
return { schema: OUTPUT_SCHEMA,
|
|
4414
|
+
psktTransactionJson: feeResult.transaction.serializeToSafeJSON(),
|
|
4415
|
+
signInputs: [{ index: fundingInputIndex, sighashType: 1 }], scripts,
|
|
4416
|
+
submitTransactionSupported: true,
|
|
4417
|
+
metadata: { builderKey: "kcc20fee.sell-into-bids",
|
|
4418
|
+
operation: "fee-market-sell-into-bids", network, walletAddress,
|
|
4419
|
+
tokenId, marketId, policyId, fillCount: legs.length,
|
|
4420
|
+
soldAmount: sold.toString(),
|
|
4421
|
+
grossSompi: legs.reduce((sum, leg) => sum + leg.gross, 0n).toString(),
|
|
4422
|
+
protocolFeeSompi: protocolTotal.toString(),
|
|
4423
|
+
creatorFeeSompi: creatorTotal.toString(), receiptOutputIndex,
|
|
4424
|
+
ticketInputIndex, ticketRefundIndex,
|
|
4425
|
+
sellerChangeIndex: changeIndex, sellerRefundIndex: refundIndex,
|
|
4426
|
+
signedMass: { compute: signedMass.computeMass.toString(),
|
|
4427
|
+
transient: signedMass.transientMass.toString(), storage: storageMass.toString() } },
|
|
4428
|
+
};
|
|
4421
4429
|
};
|
|
4430
|
+
try {
|
|
4431
|
+
return buildWithFunding(fundingEntry);
|
|
4432
|
+
}
|
|
4433
|
+
catch (initialError) {
|
|
4434
|
+
// A large funding input can increase contextual storage mass. Preserve
|
|
4435
|
+
// caller-selected inputs; otherwise try at most seven smaller live
|
|
4436
|
+
// wallet UTXO amounts without changing the trade, fees, or mass limits.
|
|
4437
|
+
const details = initialError?.builderErrorDetails;
|
|
4438
|
+
if (params.fundingOutpoint != null ||
|
|
4439
|
+
initialError?.builderErrorCode !== "TRANSACTION_MASS_EXCEEDED" ||
|
|
4440
|
+
BigInt(details?.computeMass ?? 0) > CONSOLIDATION_TARGET_TRANSACTION_MASS ||
|
|
4441
|
+
BigInt(details?.transientMass ?? 0) > CONSOLIDATION_TARGET_TRANSACTION_MASS * 2n ||
|
|
4442
|
+
BigInt(details?.storageMass ?? 0) <= CONSOLIDATION_TARGET_TRANSACTION_MASS) {
|
|
4443
|
+
throw initialError;
|
|
4444
|
+
}
|
|
4445
|
+
const skipped = [...spentEntries.map(entry => entry.outpoint), fundingEntry.outpoint];
|
|
4446
|
+
const conservativeFundingNeeded = fundingNeeded +
|
|
4447
|
+
(estimatedFundingFeeSompi > priorityFee ? estimatedFundingFeeSompi - priorityFee : 0n);
|
|
4448
|
+
const candidates = walletUtxos.entries.filter(entry => (0, sale_common_js_1.utxoAmountSompi)(entry) >= conservativeFundingNeeded &&
|
|
4449
|
+
(0, sale_common_js_1.utxoAmountSompi)(entry) < (0, sale_common_js_1.utxoAmountSompi)(fundingEntry))
|
|
4450
|
+
.sort((a, b) => (0, sale_common_js_1.utxoAmountSompi)(a) < (0, sale_common_js_1.utxoAmountSompi)(b) ? -1 :
|
|
4451
|
+
(0, sale_common_js_1.utxoAmountSompi)(a) > (0, sale_common_js_1.utxoAmountSompi)(b) ? 1 : 0);
|
|
4452
|
+
let attempted = 0;
|
|
4453
|
+
const attemptedAmounts = new Set();
|
|
4454
|
+
for (const candidate of candidates) {
|
|
4455
|
+
if (attempted === 7)
|
|
4456
|
+
break;
|
|
4457
|
+
const amountKey = (0, sale_common_js_1.utxoAmountSompi)(candidate).toString();
|
|
4458
|
+
if (attemptedAmounts.has(amountKey))
|
|
4459
|
+
continue;
|
|
4460
|
+
let selected;
|
|
4461
|
+
try {
|
|
4462
|
+
selected = (0, sale_common_js_1.selectFundingEntry)([candidate], fundingNeeded, skipped, params.fundingOutpoint);
|
|
4463
|
+
}
|
|
4464
|
+
catch {
|
|
4465
|
+
continue;
|
|
4466
|
+
}
|
|
4467
|
+
skipped.push(selected.outpoint);
|
|
4468
|
+
attemptedAmounts.add(amountKey);
|
|
4469
|
+
attempted++;
|
|
4470
|
+
try {
|
|
4471
|
+
return buildWithFunding(selected);
|
|
4472
|
+
}
|
|
4473
|
+
catch (error) {
|
|
4474
|
+
if (!["TRANSACTION_MASS_EXCEEDED", "KAS_FUNDING_CHANGE_TOO_SMALL",
|
|
4475
|
+
"KAS_FUNDING_FEE_INSUFFICIENT"].includes(error?.builderErrorCode))
|
|
4476
|
+
throw error;
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
throw initialError;
|
|
4480
|
+
}
|
|
4422
4481
|
}
|
|
4423
4482
|
finally {
|
|
4424
4483
|
await rpc.disconnect();
|