@kaspacom/kcc20-tx-builder 0.2.5 → 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/CHANGELOG.md +26 -0
- package/README.md +54 -8
- package/RELEASING.md +93 -0
- package/SECURITY.md +16 -0
- package/artifacts/KCC20SnapshotBootstrap.placeholder.json +101677 -0
- package/artifacts/KCC20SnapshotController.placeholder.json +46547 -0
- package/artifacts/kcc20-snapshot-bootstrap/KCC20SnapshotBootstrap.placeholder.json +101677 -0
- package/artifacts/kcc20-snapshot-controller/KCC20SnapshotController.placeholder.json +46547 -0
- package/artifacts/snapshot-standards.lock.json +56 -0
- package/dist/artifacts.d.ts +31 -0
- package/dist/artifacts.d.ts.map +1 -1
- package/dist/artifacts.js +31 -0
- package/dist/artifacts.js.map +1 -1
- package/dist/cjs/artifacts.d.ts +31 -0
- package/dist/cjs/artifacts.js +32 -1
- package/dist/cjs/artifacts.js.map +1 -1
- package/dist/cjs/engine.js +58 -44
- package/dist/cjs/engine.js.map +1 -1
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/operations.d.ts +1 -1
- package/dist/cjs/operations.js +4 -0
- package/dist/cjs/operations.js.map +1 -1
- package/dist/cjs/sale-common.d.ts +1 -1
- package/dist/cjs/sale-common.js +39 -4
- package/dist/cjs/sale-common.js.map +1 -1
- package/dist/cjs/snapshot-deployment.d.ts +82 -0
- package/dist/cjs/snapshot-deployment.js +82 -0
- package/dist/cjs/snapshot-deployment.js.map +1 -0
- package/dist/cjs/snapshot-operation.d.ts +26 -0
- package/dist/cjs/snapshot-operation.js +1308 -0
- package/dist/cjs/snapshot-operation.js.map +1 -0
- package/dist/cjs/snapshot-signerless-transactions.d.ts +132 -0
- package/dist/cjs/snapshot-signerless-transactions.js +746 -0
- package/dist/cjs/snapshot-signerless-transactions.js.map +1 -0
- package/dist/cjs/snapshot-signerless.d.ts +226 -0
- package/dist/cjs/snapshot-signerless.js +1022 -0
- package/dist/cjs/snapshot-signerless.js.map +1 -0
- package/dist/cjs/snapshot-verification.d.ts +57 -0
- package/dist/cjs/snapshot-verification.js +100 -0
- package/dist/cjs/snapshot-verification.js.map +1 -0
- package/dist/cjs/token-operation.js +3 -3
- package/dist/cjs/token-operation.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +58 -44
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/operations.d.ts +1 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +4 -0
- package/dist/operations.js.map +1 -1
- package/dist/sale-common.d.ts +1 -1
- package/dist/sale-common.d.ts.map +1 -1
- package/dist/sale-common.js +39 -4
- package/dist/sale-common.js.map +1 -1
- package/dist/snapshot-deployment.d.ts +83 -0
- package/dist/snapshot-deployment.d.ts.map +1 -0
- package/dist/snapshot-deployment.js +78 -0
- package/dist/snapshot-deployment.js.map +1 -0
- package/dist/snapshot-operation.d.ts +27 -0
- package/dist/snapshot-operation.d.ts.map +1 -0
- package/dist/snapshot-operation.js +1303 -0
- package/dist/snapshot-operation.js.map +1 -0
- package/dist/snapshot-signerless-transactions.d.ts +133 -0
- package/dist/snapshot-signerless-transactions.d.ts.map +1 -0
- package/dist/snapshot-signerless-transactions.js +735 -0
- package/dist/snapshot-signerless-transactions.js.map +1 -0
- package/dist/snapshot-signerless.d.ts +227 -0
- package/dist/snapshot-signerless.d.ts.map +1 -0
- package/dist/snapshot-signerless.js +993 -0
- package/dist/snapshot-signerless.js.map +1 -0
- package/dist/snapshot-verification.d.ts +58 -0
- package/dist/snapshot-verification.d.ts.map +1 -0
- package/dist/snapshot-verification.js +96 -0
- package/dist/snapshot-verification.js.map +1 -0
- package/dist/token-operation.js +3 -3
- package/dist/token-operation.js.map +1 -1
- package/docs/API.md +67 -0
- package/docs/COMPATIBILITY.json +84 -0
- package/docs/INTEGRATION.md +215 -0
- package/docs/LIVE_TRANSFER.md +106 -0
- package/docs/RECIPES.md +175 -0
- package/docs/TRANSACTION_GUIDE.md +163 -0
- package/docs/snapshot-start.md +27 -0
- package/examples/README.md +81 -0
- package/examples/backend/cli.ts +55 -0
- package/examples/backend/recipe.ts +39 -0
- package/examples/backend/runtime.ts +13 -0
- package/examples/frontend/index.html +48 -0
- package/examples/frontend/main.ts +213 -0
- package/examples/frontend/runtime.ts +14 -0
- package/examples/package-lock.json +1287 -0
- package/examples/package.json +23 -0
- package/examples/shared/build.ts +179 -0
- package/examples/shared/fixture.ts +24 -0
- package/examples/shared/live-transfer.ts +155 -0
- package/examples/shared/recipe-fixtures.ts +543 -0
- package/examples/shared/recipes.ts +55 -0
- package/examples/shared/signing.ts +110 -0
- package/examples/shared/timeout.ts +8 -0
- package/examples/test/browser.ts +116 -0
- package/examples/test/build.test.ts +197 -0
- package/examples/test/recipes.test.ts +59 -0
- package/examples/test/sources.test.ts +73 -0
- package/examples/tsconfig.json +26 -0
- package/examples/vendor/NOTICE.md +15 -0
- package/examples/vendor/kaspa/LICENSE +15 -0
- package/examples/vendor/kaspa/kaspa.d.ts +8908 -0
- package/examples/vendor/kaspa/kaspa.js +15202 -0
- package/examples/vendor/kaspa/kaspa_bg.wasm +0 -0
- package/examples/vendor/kaspa/package.json +24 -0
- package/package.json +21 -4
- package/src/artifacts.ts +35 -0
- package/src/engine.ts +91 -97
- package/src/index.ts +8 -0
- package/src/operations.ts +4 -0
- package/src/sale-common.ts +44 -3
- package/src/snapshot-deployment.ts +108 -0
- package/src/snapshot-operation.ts +1920 -0
- package/src/snapshot-signerless-transactions.ts +1272 -0
- package/src/snapshot-signerless.ts +1525 -0
- package/src/snapshot-verification.ts +90 -0
- package/src/token-operation.ts +3 -3
package/src/sale-common.ts
CHANGED
|
@@ -1135,8 +1135,16 @@ export function selectFundingEntry(
|
|
|
1135
1135
|
entries,
|
|
1136
1136
|
requiredSompi,
|
|
1137
1137
|
skippedOutpoints = [],
|
|
1138
|
+
requiredOutpoint = undefined,
|
|
1138
1139
|
) {
|
|
1139
|
-
const skipped = new Set(skippedOutpoints);
|
|
1140
|
+
const skipped = new Set(skippedOutpoints.map(normalizeFundingOutpoint));
|
|
1141
|
+
const pinned =
|
|
1142
|
+
requiredOutpoint === undefined || requiredOutpoint === null
|
|
1143
|
+
? undefined
|
|
1144
|
+
: normalizeFundingOutpoint(requiredOutpoint);
|
|
1145
|
+
if (pinned !== undefined && !pinned) {
|
|
1146
|
+
throw new Error("pinned funding outpoint is invalid");
|
|
1147
|
+
}
|
|
1140
1148
|
const sorted = [...entries].sort((a, b) => {
|
|
1141
1149
|
const av = utxoAmountSompi(a);
|
|
1142
1150
|
const bv = utxoAmountSompi(b);
|
|
@@ -1144,17 +1152,50 @@ export function selectFundingEntry(
|
|
|
1144
1152
|
return av < bv ? 1 : -1;
|
|
1145
1153
|
});
|
|
1146
1154
|
const entry = sorted.find((candidate) => {
|
|
1147
|
-
const outpoint =
|
|
1155
|
+
const outpoint = normalizeFundingOutpoint(candidate.outpoint);
|
|
1148
1156
|
return (
|
|
1149
|
-
!
|
|
1157
|
+
(!pinned || outpoint === pinned) &&
|
|
1158
|
+
!skipped.has(outpoint) &&
|
|
1159
|
+
utxoAmountSompi(candidate) >= requiredSompi
|
|
1150
1160
|
);
|
|
1151
1161
|
});
|
|
1152
1162
|
if (!entry) {
|
|
1163
|
+
if (pinned) {
|
|
1164
|
+
throw new Error(
|
|
1165
|
+
`pinned funding UTXO ${pinned} is unavailable or cannot cover ${requiredSompi} sompi`,
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1153
1168
|
throw new Error(`no single funding UTXO can cover ${requiredSompi} sompi`);
|
|
1154
1169
|
}
|
|
1155
1170
|
return entry;
|
|
1156
1171
|
}
|
|
1157
1172
|
|
|
1173
|
+
function normalizeFundingOutpoint(value) {
|
|
1174
|
+
if (typeof value === "string") {
|
|
1175
|
+
const match = value
|
|
1176
|
+
.trim()
|
|
1177
|
+
.toLowerCase()
|
|
1178
|
+
.match(/^([a-f0-9]{64}):(\d+)$/);
|
|
1179
|
+
if (!match) return "";
|
|
1180
|
+
const index = Number(match[2]);
|
|
1181
|
+
return Number.isSafeInteger(index) && index >= 0 && index <= 0xffffffff
|
|
1182
|
+
? `${match[1]}:${index}`
|
|
1183
|
+
: "";
|
|
1184
|
+
}
|
|
1185
|
+
const transactionId = String(
|
|
1186
|
+
value?.transactionId ?? value?.transactionIdHex ?? value?.txid ?? "",
|
|
1187
|
+
)
|
|
1188
|
+
.trim()
|
|
1189
|
+
.toLowerCase();
|
|
1190
|
+
const index = Number(value?.index ?? value?.vout);
|
|
1191
|
+
return /^[a-f0-9]{64}$/.test(transactionId) &&
|
|
1192
|
+
Number.isSafeInteger(index) &&
|
|
1193
|
+
index >= 0 &&
|
|
1194
|
+
index <= 0xffffffff
|
|
1195
|
+
? `${transactionId}:${index}`
|
|
1196
|
+
: "";
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1158
1199
|
export function requiredToccataFeeSompi(kw, network, transaction) {
|
|
1159
1200
|
if (
|
|
1160
1201
|
typeof kw.calculateTransactionFee !== "function" ||
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { bytesToHex, asciiToBytes32 } from "./encoding.js";
|
|
2
|
+
import { assertKcc20ArtifactScriptHash } from "./artifacts.js";
|
|
3
|
+
import {
|
|
4
|
+
buildControllerGenesisPlan, buildBootstrapGenesisPlan,
|
|
5
|
+
buildSnapshotStartPlan, buildSnapshotTokenMetadata, snapshotPeerPlanCommitment,
|
|
6
|
+
} from "./snapshot-signerless.js";
|
|
7
|
+
import { deriveSnapshotTokenId } from "./snapshot-signerless-transactions.js";
|
|
8
|
+
|
|
9
|
+
export const SNAPSHOT_DEPLOYMENT_PROTOCOL = "signerless-start-v2" as const;
|
|
10
|
+
export interface SnapshotDeploymentShard {
|
|
11
|
+
shardIndex: number;
|
|
12
|
+
globalIndexStart: number;
|
|
13
|
+
holderCount: number;
|
|
14
|
+
depth: number;
|
|
15
|
+
allocationTotal: string;
|
|
16
|
+
initialRoot: string;
|
|
17
|
+
controllerId?: string;
|
|
18
|
+
genesisOutpoint?: { transactionId: string; index: number };
|
|
19
|
+
}
|
|
20
|
+
export interface SnapshotDeploymentDefinition {
|
|
21
|
+
migrationId: string;
|
|
22
|
+
manifestCommitment: string;
|
|
23
|
+
context: string;
|
|
24
|
+
creator: string;
|
|
25
|
+
ticker: string;
|
|
26
|
+
displayScale: string;
|
|
27
|
+
totalSupply: string;
|
|
28
|
+
claimNotBeforeDaaScore: string;
|
|
29
|
+
shards: SnapshotDeploymentShard[];
|
|
30
|
+
bootstrapId?: string;
|
|
31
|
+
bootstrapOutpoint?: { transactionId: string; index: number };
|
|
32
|
+
}
|
|
33
|
+
export interface SnapshotArtifacts {
|
|
34
|
+
controllerArtifact: any;
|
|
35
|
+
bootstrapArtifact: any;
|
|
36
|
+
kcc20Artifact: any;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Pure deterministic planning. IDs must come from independently confirmed genesis outputs. */
|
|
40
|
+
export function prepareSnapshotDeployment(kw: any, definition: SnapshotDeploymentDefinition, artifacts: SnapshotArtifacts) {
|
|
41
|
+
assertKcc20ArtifactScriptHash("KCC20.placeholder.json", artifacts.kcc20Artifact);
|
|
42
|
+
assertKcc20ArtifactScriptHash("KCC20SnapshotBootstrap.placeholder.json", artifacts.bootstrapArtifact);
|
|
43
|
+
assertKcc20ArtifactScriptHash("KCC20SnapshotController.placeholder.json", artifacts.controllerArtifact);
|
|
44
|
+
const shards = [...definition.shards].sort((a, b) => a.shardIndex - b.shardIndex);
|
|
45
|
+
if (!shards.length || shards.length > 8 || shards.some((s, i) => s.shardIndex !== i)) {
|
|
46
|
+
throw new Error("snapshot requires 1..8 contiguous shards");
|
|
47
|
+
}
|
|
48
|
+
if (shards.reduce((sum, shard) => sum + BigInt(shard.allocationTotal), 0n) !== BigInt(definition.totalSupply)) {
|
|
49
|
+
throw new Error("shard allocations do not equal fixed token supply");
|
|
50
|
+
}
|
|
51
|
+
const extension = {
|
|
52
|
+
kind: 1, creator: definition.creator, ticker: bytesToHex(asciiToBytes32(definition.ticker)),
|
|
53
|
+
name: bytesToHex(asciiToBytes32(definition.ticker)), displayScale: definition.displayScale,
|
|
54
|
+
maxSupply: definition.totalSupply, mintLaneCount: 1, mintPolicy: 0, mintPriceSompi: "0",
|
|
55
|
+
treasury: definition.creator, protocolFeeRecipient: definition.creator, protocolFeeBps: "0",
|
|
56
|
+
};
|
|
57
|
+
const metadata = buildSnapshotTokenMetadata({
|
|
58
|
+
...extension, migrationId: definition.migrationId, totalAllocation: definition.totalSupply,
|
|
59
|
+
} as any);
|
|
60
|
+
const common = {
|
|
61
|
+
...artifacts, migrationId: definition.migrationId, migrationCommitment: definition.migrationId,
|
|
62
|
+
manifestCommitment: definition.manifestCommitment, context: definition.context,
|
|
63
|
+
holderExtensionCommitment: metadata.holderExtensionCommitment,
|
|
64
|
+
claimNotBeforeDaaScore: definition.claimNotBeforeDaaScore, shardCount: shards.length,
|
|
65
|
+
};
|
|
66
|
+
const placeholder = "01".repeat(32);
|
|
67
|
+
const controllerPlans = shards.map(shard => buildControllerGenesisPlan({
|
|
68
|
+
...common, shard, deploymentGuardCommitment: shard.shardIndex === 0 ? placeholder : "00".repeat(32),
|
|
69
|
+
} as any));
|
|
70
|
+
const peerPending = shards.slice(1).find(s => !s.controllerId || !s.genesisOutpoint);
|
|
71
|
+
if (peerPending) return {
|
|
72
|
+
stage: "controller-deploy" as const, shard: peerPending.shardIndex,
|
|
73
|
+
plan: controllerPlans[peerPending.shardIndex], holderExtensionCommitment: metadata.holderExtensionCommitment,
|
|
74
|
+
extension,
|
|
75
|
+
};
|
|
76
|
+
const peerCommitment = snapshotPeerPlanCommitment({
|
|
77
|
+
migrationCommitment: definition.migrationId, manifestCommitment: definition.manifestCommitment,
|
|
78
|
+
shards: shards.map((shard, i) => ({ controllerId: shard.controllerId ?? placeholder, state: controllerPlans[i].controllerState })),
|
|
79
|
+
});
|
|
80
|
+
controllerPlans[0] = buildControllerGenesisPlan({
|
|
81
|
+
...common, shard: shards[0], deploymentGuardCommitment: peerCommitment,
|
|
82
|
+
} as any);
|
|
83
|
+
if (!shards[0].controllerId || !shards[0].genesisOutpoint) return {
|
|
84
|
+
stage: "controller-deploy" as const, shard: 0, plan: controllerPlans[0],
|
|
85
|
+
holderExtensionCommitment: metadata.holderExtensionCommitment, extension,
|
|
86
|
+
};
|
|
87
|
+
const committedShards = shards.map((shard, i) => ({ controllerId: shard.controllerId!, state: controllerPlans[i].controllerState }));
|
|
88
|
+
const reserves = shards.map(shard => ({
|
|
89
|
+
amount: shard.allocationTotal, owner: shard.controllerId!, ownerScheme: 4,
|
|
90
|
+
borrowScheme: 0, borrowGuard: "00".repeat(32), extensionCommitment: metadata.holderExtensionCommitment,
|
|
91
|
+
}));
|
|
92
|
+
const tokenId = deriveSnapshotTokenId(kw, {
|
|
93
|
+
controllerGenesisOutpoint: shards[0].genesisOutpoint, reserves, kcc20Artifact: artifacts.kcc20Artifact,
|
|
94
|
+
reserveCellKas: "50000000",
|
|
95
|
+
});
|
|
96
|
+
const bootstrapPlan = buildBootstrapGenesisPlan({
|
|
97
|
+
...common, expectedTokenId: tokenId, totalSupply: definition.totalSupply, shards: committedShards,
|
|
98
|
+
} as any);
|
|
99
|
+
return {
|
|
100
|
+
stage: definition.bootstrapId ? "snapshot-start" as const : "bootstrap-deploy" as const,
|
|
101
|
+
plan: definition.bootstrapId ? buildSnapshotStartPlan({
|
|
102
|
+
...artifacts, migrationId: definition.migrationId, bootstrapId: definition.bootstrapId,
|
|
103
|
+
bootstrapState: bootstrapPlan.bootstrapState, shards: committedShards,
|
|
104
|
+
}) : bootstrapPlan,
|
|
105
|
+
tokenId, holderExtensionCommitment: metadata.holderExtensionCommitment,
|
|
106
|
+
extension, controllers: committedShards,
|
|
107
|
+
};
|
|
108
|
+
}
|