@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
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Integrating the TX Builder
|
|
2
|
+
|
|
3
|
+
This guide describes the API shipped in `@kaspacom/kcc20-tx-builder@0.5.0`.
|
|
4
|
+
The host application supplies wallet identity, network configuration, contract
|
|
5
|
+
artifacts, chain data, and an initialized Kaspa WASM runtime. The package
|
|
6
|
+
constructs operations and transaction JSON. The host signs, validates,
|
|
7
|
+
broadcasts, and tracks the result.
|
|
8
|
+
|
|
9
|
+
## Install from the public registry
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install --save-exact @kaspacom/kcc20-tx-builder@0.5.0 \
|
|
13
|
+
--registry=https://registry.npmjs.org/ \
|
|
14
|
+
--@kaspacom:registry=https://registry.npmjs.org/
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The scoped registry option matters when a project or user `.npmrc` maps
|
|
18
|
+
`@kaspacom` to GitHub Packages. Public npm installation does not require a
|
|
19
|
+
GitHub token. Commit your lockfile and pin the same package version across
|
|
20
|
+
browser and server adapters.
|
|
21
|
+
|
|
22
|
+
Node consumers need Node.js 20 or newer. Browser consumers need a bundler
|
|
23
|
+
that supports ESM and their platform's Kaspa WASM build. ESM and CommonJS
|
|
24
|
+
exports are available:
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
import { KCC20_PSKT_BUILDER_INPUT_SCHEMA } from '@kaspacom/kcc20-tx-builder';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
const { KCC20_PSKT_BUILDER_INPUT_SCHEMA } = require('@kaspacom/kcc20-tx-builder');
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Start with amount calculations
|
|
35
|
+
|
|
36
|
+
This example runs without a wallet, RPC connection, or WASM runtime:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import {
|
|
40
|
+
parseKcc20DisplayAmountToBaseUnits,
|
|
41
|
+
formatKcc20BaseUnitsForDisplay,
|
|
42
|
+
calculateKcc20OrderTotalSompi,
|
|
43
|
+
} from '@kaspacom/kcc20-tx-builder';
|
|
44
|
+
|
|
45
|
+
const baseUnits = parseKcc20DisplayAmountToBaseUnits('1.25', 8, 'amount');
|
|
46
|
+
console.log(baseUnits); // '125000000'
|
|
47
|
+
console.log(formatKcc20BaseUnitsForDisplay(baseUnits, 8)); // '1.25'
|
|
48
|
+
|
|
49
|
+
const order = calculateKcc20OrderTotalSompi('1.25', '100000000', 8);
|
|
50
|
+
console.log(order?.totalSompi); // '125000000'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Use decimal strings for token amounts and sompi values. Use `bigint` for
|
|
54
|
+
arithmetic. A token's display decimals are separate from the KAS unit scale;
|
|
55
|
+
read them from its verified metadata. The helpers accept token decimals from
|
|
56
|
+
0 through 8. Check `roundedDown` and `roundedTokenAmountBaseUnits` when quoting
|
|
57
|
+
orders because some prices require rounding to an exact sompi amount.
|
|
58
|
+
|
|
59
|
+
## Configure a persistent engine
|
|
60
|
+
|
|
61
|
+
The following adapter is TypeScript. Its parameters are dependencies supplied
|
|
62
|
+
by your application, not objects exported by the package:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import {
|
|
66
|
+
createKcc20PsktBuilderEngine,
|
|
67
|
+
type KaspaWasmRuntime,
|
|
68
|
+
type Kcc20PsktBuilderInput,
|
|
69
|
+
} from '@kaspacom/kcc20-tx-builder';
|
|
70
|
+
|
|
71
|
+
export function createWalletBuilder(
|
|
72
|
+
loadedKaspa: KaspaWasmRuntime,
|
|
73
|
+
applicationRpcConnection: {
|
|
74
|
+
getUtxosByAddresses(request: { addresses: string[] }): Promise<unknown>;
|
|
75
|
+
},
|
|
76
|
+
artifactProvider: (key: string) => Promise<unknown>,
|
|
77
|
+
) {
|
|
78
|
+
const engine = createKcc20PsktBuilderEngine({
|
|
79
|
+
wasm: loadedKaspa,
|
|
80
|
+
artifacts: {},
|
|
81
|
+
artifactProvider,
|
|
82
|
+
config: { KASPA_NETWORK: 'testnet-10' },
|
|
83
|
+
sourceProvider: {
|
|
84
|
+
getUtxosByAddresses: (request) =>
|
|
85
|
+
applicationRpcConnection.getUtxosByAddresses(request),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return (preparedInput: Kcc20PsktBuilderInput) => engine.build(preparedInput);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Initialize WASM before calling this adapter. Select and connect your RPC
|
|
94
|
+
endpoint in the host. The builder does not connect or disconnect a supplied
|
|
95
|
+
`sourceProvider`. Reuse a persistent engine to retain its artifact cache.
|
|
96
|
+
Supply fresh indexed covenant state and wallet funding sources for each build.
|
|
97
|
+
|
|
98
|
+
For a browser, serve the package's JSON artifacts through your asset pipeline:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
export async function artifactProvider(key: string): Promise<unknown> {
|
|
102
|
+
const response = await fetch(`/kcc20-artifacts/${encodeURIComponent(key)}`);
|
|
103
|
+
if (!response.ok) throw new Error(`Cannot load artifact ${key}: ${response.status}`);
|
|
104
|
+
const rawBytes = new Uint8Array(await response.arrayBuffer());
|
|
105
|
+
return {
|
|
106
|
+
artifact: JSON.parse(new TextDecoder().decode(rawBytes)),
|
|
107
|
+
rawBytes,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Copy the installed package's `artifacts/*.json` files to that asset directory
|
|
113
|
+
as part of the host build. A server can load those same files once using its
|
|
114
|
+
own filesystem adapter and pass an envelope containing both the parsed
|
|
115
|
+
`artifact` and its exact `rawBytes` through `artifacts`. Snapshot builders
|
|
116
|
+
require those bytes to verify the frozen SHA-256 artifact pins.
|
|
117
|
+
Filesystem access belongs in the host, outside this package.
|
|
118
|
+
|
|
119
|
+
`rpcClientFactory` is an alternative for hosts that need the builder to create
|
|
120
|
+
an RPC client. Prefer `sourceProvider` when the application already owns a
|
|
121
|
+
connection. Configure network and RPC explicitly rather than relying on the
|
|
122
|
+
engine's TN10 defaults.
|
|
123
|
+
|
|
124
|
+
## Prepare the input
|
|
125
|
+
|
|
126
|
+
The engine accepts the in-process envelope:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import {
|
|
130
|
+
KCC20_PSKT_BUILDER_INPUT_SCHEMA,
|
|
131
|
+
type Kcc20PsktBuilderInput,
|
|
132
|
+
} from '@kaspacom/kcc20-tx-builder';
|
|
133
|
+
|
|
134
|
+
export function toBuilderInput(
|
|
135
|
+
preparedRequest: Record<string, unknown>,
|
|
136
|
+
): Kcc20PsktBuilderInput {
|
|
137
|
+
return {
|
|
138
|
+
schema: KCC20_PSKT_BUILDER_INPUT_SCHEMA,
|
|
139
|
+
builder: {},
|
|
140
|
+
request: preparedRequest,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`request.builderKey` selects the operation. The remaining request fields are
|
|
146
|
+
operation-specific: wallet owner and address, network, params, and decoded
|
|
147
|
+
covenant sources. This envelope adapter does not prepare or validate them.
|
|
148
|
+
Use the operation helpers listed in [the API guide](API.md) to construct intent,
|
|
149
|
+
then let your host resolve the required sources and assemble the engine request.
|
|
150
|
+
There is no universal funded request that works for every operation.
|
|
151
|
+
|
|
152
|
+
Operation helpers such as `buildKcc20TransferTokenOperation` return a wallet
|
|
153
|
+
operation envelope with an initially missing funded PSKT. That object is not
|
|
154
|
+
directly an engine input. The host must convert its intent and sources into
|
|
155
|
+
`request`, build the PSKT, and attach the funded result to its signing flow.
|
|
156
|
+
|
|
157
|
+
Do not confuse `KCC20_PSKT_BUILDER_INPUT_SCHEMA` with
|
|
158
|
+
`KCC20_BUILDER_INPUT_SCHEMA` from `models.ts`. The latter describes the separate
|
|
159
|
+
shared source/context model. Passing that model directly to `engine.build`
|
|
160
|
+
fails its schema check.
|
|
161
|
+
|
|
162
|
+
## Consume the result
|
|
163
|
+
|
|
164
|
+
The engine returns an operation-specific record with
|
|
165
|
+
`schema: 'kcc20-in-process-pskt-builder-output/v1'`, `psktTransactionJson`,
|
|
166
|
+
`signInputs`, and, where needed, covenant `scripts` and `metadata`.
|
|
167
|
+
`psktTransactionJson` is JSON text, not an already signed transaction.
|
|
168
|
+
The return type is `Record<string, unknown>`; narrow and validate the fields
|
|
169
|
+
your wallet adapter consumes.
|
|
170
|
+
|
|
171
|
+
1. Present the intended action, amounts, recipients, and fees to the user.
|
|
172
|
+
2. Build using fresh sources and check the resulting inputs and outputs.
|
|
173
|
+
3. Use the wallet's PSKT signing interface with the returned signing instructions.
|
|
174
|
+
4. Independently validate the signed transaction and authorization in your trusted host.
|
|
175
|
+
5. Broadcast through your host and reconcile confirmation or reorg state through your indexer.
|
|
176
|
+
|
|
177
|
+
The package does not provide wallet discovery, signing UI, authentication,
|
|
178
|
+
broadcast orchestration, or confirmation tracking. Browser-built transaction
|
|
179
|
+
JSON remains untrusted input at a backend boundary.
|
|
180
|
+
|
|
181
|
+
## Artifacts and privileged builders
|
|
182
|
+
|
|
183
|
+
The package pins script hashes for five shipped artifacts. The engine validates
|
|
184
|
+
artifacts against those hashes; mixing independently compiled artifacts with
|
|
185
|
+
this package version can fail the build. Upgrade artifacts and builder together.
|
|
186
|
+
JSON subpath loading depends on the host's module loader, so the asset-provider
|
|
187
|
+
approach avoids imposing a JSON import syntax on consumers.
|
|
188
|
+
|
|
189
|
+
`allowBackendOnly` defaults to disabled. The matcher builder
|
|
190
|
+
`kcc20orderbook.matcher-settle-crossed` requires an engine explicitly configured
|
|
191
|
+
with `allowBackendOnly: true` in a trusted server. That flag does not authorize
|
|
192
|
+
a caller. Keep matcher scheduling, authorization, and any private keys in the
|
|
193
|
+
server host. `buildKcc20Pskt` does not expose this opt-in; configure an engine
|
|
194
|
+
for privileged work.
|
|
195
|
+
|
|
196
|
+
## Handle errors
|
|
197
|
+
|
|
198
|
+
Some helpers throw `Kcc20BuilderError`, exposing `code` and string-valued
|
|
199
|
+
`details`. Other helpers and the engine throw ordinary `Error` instances;
|
|
200
|
+
do not assume every failure has a structured code. Handle both:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { Kcc20BuilderError } from '@kaspacom/kcc20-tx-builder';
|
|
204
|
+
|
|
205
|
+
export function describeBuildFailure(error: unknown): string {
|
|
206
|
+
if (error instanceof Kcc20BuilderError) return `${error.code}: ${error.message}`;
|
|
207
|
+
if (error instanceof Error) return error.message;
|
|
208
|
+
return 'Transaction construction failed';
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Refresh sources after spent or stale UTXO failures. An artifact mismatch needs
|
|
213
|
+
a package/artifact compatibility check. A missing WASM capability needs a
|
|
214
|
+
compatible runtime. Do not retry signing or broadcast automatically after an
|
|
215
|
+
ambiguous submission; reconcile its transaction ID in your host first.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Transfer using your own indexer and RPC
|
|
2
|
+
|
|
3
|
+
The browser and Node examples use the same
|
|
4
|
+
[`liveTransferOperation`](../examples/shared/live-transfer.ts) adapter. It retrieves
|
|
5
|
+
decoded holder state from an endpoint you configure, confirms the output through
|
|
6
|
+
RPC, and passes the validated holder to the existing transfer helper. No KaspaCom
|
|
7
|
+
application backend is involved.
|
|
8
|
+
|
|
9
|
+
## Decoded-state endpoint
|
|
10
|
+
|
|
11
|
+
Serve an HTTP GET endpoint returning:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { Kcc20IndexedCovenantUtxo } from "@kaspacom/kcc20-tx-builder/action-source-resolver";
|
|
15
|
+
type HolderResponse = {
|
|
16
|
+
network: "testnet-10";
|
|
17
|
+
utxos: Kcc20IndexedCovenantUtxo[];
|
|
18
|
+
};
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Map your indexer's transaction ID, output index, KAS amount, native covenant ID,
|
|
22
|
+
address and decoded state to this shape. An application alias must not replace
|
|
23
|
+
the native covenant ID. Amounts must be decimal strings. This adapter supports
|
|
24
|
+
unborrowed native holders owned by a Schnorr public key. It rejects duplicate
|
|
25
|
+
outpoints and malformed rows. Paginate in your indexer adapter if a response
|
|
26
|
+
would exceed 1,000 rows.
|
|
27
|
+
|
|
28
|
+
A complete deterministic response can be generated without a backend:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
cd examples
|
|
32
|
+
npm run --silent recipe -- transfer --arguments > transfer-arguments.json
|
|
33
|
+
node --input-type=module -e 'import fs from "node:fs"; const a=JSON.parse(fs.readFileSync("transfer-arguments.json")); console.log(JSON.stringify({network:"testnet-10",utxos:a[1].activeUtxos},null,2))' > holder-response.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This includes actual address strings, outpoints, base-unit amounts, native IDs,
|
|
37
|
+
owner identifiers, extension commitments and borrow fields. All outpoints are
|
|
38
|
+
synthetic. They demonstrate the schema and are rejected by a live node.
|
|
39
|
+
|
|
40
|
+
For real use, fill these fields from your indexer's decoded current outputs.
|
|
41
|
+
RPC alone does not provide token amount, owner scheme or extension commitment.
|
|
42
|
+
The adapter rebuilds the holder script from decoded state and the packaged
|
|
43
|
+
artifact, verifies its address, then checks the RPC outpoint, script, KAS amount
|
|
44
|
+
and native covenant ID. A fabricated or stale snapshot cannot bypass those
|
|
45
|
+
comparisons. The selected RPC remains a trusted source of chain data.
|
|
46
|
+
|
|
47
|
+
## Transfer configuration
|
|
48
|
+
|
|
49
|
+
Save `transfer.json` in `examples`. Replace the marked values with your own
|
|
50
|
+
TN10 account and verified token metadata:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"network": "testnet-10",
|
|
55
|
+
"stateUrl": "https://your-indexer.example/holders",
|
|
56
|
+
"wallet": {
|
|
57
|
+
"walletAddress": "kaspatest:YOUR_ADDRESS",
|
|
58
|
+
"kcc20Owner": "YOUR_64_HEX_OWNER"
|
|
59
|
+
},
|
|
60
|
+
"covenantId": "YOUR_64_HEX_NATIVE_COVENANT_ID",
|
|
61
|
+
"decimals": 2,
|
|
62
|
+
"recipientOwner": "RECIPIENT_64_HEX_OWNER",
|
|
63
|
+
"tokenAmount": "12.50"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
TypeScript applications can import `LiveTransferConfig` from the shared adapter.
|
|
68
|
+
`decimals` comes from verified token metadata. It determines the requested base
|
|
69
|
+
units; it cannot be inferred from a holder amount. The recipient is an x-only
|
|
70
|
+
public key. The adapter checks that the sender address belongs to the supplied
|
|
71
|
+
owner key. This example requires one holder large enough for the transfer and
|
|
72
|
+
separate KAS funding. Use the consolidation recipe for fragmented balances.
|
|
73
|
+
|
|
74
|
+
## Backend
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
cd examples
|
|
78
|
+
KASPA_WRPC_URL=wss://your-tn10-node npm run --silent backend -- transfer transfer.json > unsigned.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The CLI checks the connected node's network, retrieves and validates the holder,
|
|
82
|
+
builds locally, writes the unsigned transaction and signing instructions, and
|
|
83
|
+
closes RPC. A server handler can call the same adapter with a process-owned
|
|
84
|
+
connection. Apply authorization before any server signing. Do not accept arbitrary
|
|
85
|
+
state URLs from unauthenticated callers: configure or allowlist indexer endpoints
|
|
86
|
+
in your own server to avoid turning it into an HTTP proxy.
|
|
87
|
+
|
|
88
|
+
## Frontend
|
|
89
|
+
|
|
90
|
+
Start the Vite example, enter the RPC URL, paste the same configuration JSON into
|
|
91
|
+
the text area, and click **Build transfer from indexer**. The state endpoint must
|
|
92
|
+
allow your application's origin through CORS. HTTPS applications need HTTPS state
|
|
93
|
+
URLs and WSS RPC. Review the complete unsigned transaction before the separate
|
|
94
|
+
**Sign** and **Broadcast** actions.
|
|
95
|
+
|
|
96
|
+
The same function can be imported directly:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const operation = await liveTransferOperation(wasm, rpc, loadArtifact, config);
|
|
100
|
+
const unsigned = await createBuilder(wasm, rpc, loadArtifact)(operation);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The network check belongs to the host connection setup, as shown in both runnable
|
|
104
|
+
apps. An input can be spent after validation: on a node rejection, refresh state
|
|
105
|
+
and rebuild. If submission times out, check the transaction ID and spent inputs
|
|
106
|
+
before retrying. These examples do not claim live wallet or node acceptance.
|
package/docs/RECIPES.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Operation recipes
|
|
2
|
+
|
|
3
|
+
The [recipe registry](../examples/shared/recipes.ts) imports the package's existing
|
|
4
|
+
helpers with their original TypeScript signatures. These helpers describe an
|
|
5
|
+
operation; the shared `createBuilder` adapter constructs its transaction locally.
|
|
6
|
+
All examples target TN10. Supply current decoded state from your own indexer or
|
|
7
|
+
transaction decoder, plus current UTXOs from your own RPC connection.
|
|
8
|
+
|
|
9
|
+
## Run a helper and build its transaction
|
|
10
|
+
|
|
11
|
+
Save a JSON array containing the helper's arguments, in signature order, to
|
|
12
|
+
`arguments.json`. The CLI calls the selected helper and emits its operation:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
cd examples
|
|
16
|
+
npm run --silent recipe -- deploy arguments.json > operation.json
|
|
17
|
+
KASPA_WRPC_URL=wss://your-tn10-node npm run --silent backend -- build operation.json > unsigned.json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
For frontend applications, use the same typed registry directly:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { recipes } from "./shared/recipes";
|
|
24
|
+
const operation = recipes.deploy(
|
|
25
|
+
wallet,
|
|
26
|
+
{
|
|
27
|
+
ticker: "DEMO",
|
|
28
|
+
tokenName: "Example token",
|
|
29
|
+
decimals: 2,
|
|
30
|
+
maxSupply: "1000",
|
|
31
|
+
premintSupply: "1000",
|
|
32
|
+
mintPolicy: "fixed",
|
|
33
|
+
mintPricePerTokenSompi: "0",
|
|
34
|
+
},
|
|
35
|
+
{ network: "testnet-10" },
|
|
36
|
+
);
|
|
37
|
+
const unsigned = await build(operation);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Complete offline recipes
|
|
41
|
+
|
|
42
|
+
Every registry entry has a complete typed argument tuple in
|
|
43
|
+
[`recipe-fixtures.ts`](../examples/shared/recipe-fixtures.ts), including decoded
|
|
44
|
+
state and matching RPC entries derived from the packaged contract scripts.
|
|
45
|
+
Run any recipe without a wallet, node or private repository:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
cd examples
|
|
49
|
+
npm run --silent recipe -- wrap --offline > unsigned-wrap.json
|
|
50
|
+
npm run --silent recipe -- wrap --arguments > wrap-arguments.json
|
|
51
|
+
npm run --silent recipe -- wrap wrap-arguments.json > wrap-operation.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Replace `wrap` with `deploy`, `transfer`, `mint`, `publicMint`, `mintAvailability`,
|
|
55
|
+
`consolidate`, `reveal`, `deployMarket`, `unwrap`, `order`, `buyOrder`, `fill`,
|
|
56
|
+
`fillBid`, `sweep`, `sweepBids`, `cancel`, `cancelBid`, `consolidateWrapped`,
|
|
57
|
+
`deployFeeTicketRoot`, `updateFeeTicketRoot`, `createFeeTicket`, `burnFeeTicket`,
|
|
58
|
+
or `transferFeeTicket`. The frontend's **Offline recipe** selector runs the same
|
|
59
|
+
fixtures and always keeps signing and broadcasting disabled.
|
|
60
|
+
|
|
61
|
+
`order`, `fill`, `sweep`, and `cancel` demonstrate the ask side. The bid variants
|
|
62
|
+
exercise the opposite side. `mint` uses the authority owner; `publicMint` uses a
|
|
63
|
+
different owner against an active public minter. The availability recipe pauses
|
|
64
|
+
that minter. Sweep fee totals come from the package's per-leg fee helper, including
|
|
65
|
+
the minimum protocol fee.
|
|
66
|
+
|
|
67
|
+
All 24 recipes build real unsigned transactions with the bundled WASM. Tests
|
|
68
|
+
assemble signatures with public test-vector keys and compare browser/Node unsigned
|
|
69
|
+
transactions and signing instructions. Fixtures are independent snapshots, not a
|
|
70
|
+
chain simulator. They reuse synthetic funding and cannot be submitted. Replace
|
|
71
|
+
them with current decoded state and RPC entries for live use; see the
|
|
72
|
+
[live transfer adapter](LIVE_TRANSFER.md) for a complete retrieval example.
|
|
73
|
+
|
|
74
|
+
## Native tokens
|
|
75
|
+
|
|
76
|
+
| Recipe | Existing helper | Inputs beyond the wallet |
|
|
77
|
+
| ------------------ | ---------------------------------------- | ------------------------------------------------------------------------------- |
|
|
78
|
+
| `deploy` | `buildKcc20DeployTokenOperation` | Draft supplies, decimals, mint policy, treasury and protocol fee configuration. |
|
|
79
|
+
| `transfer` | `buildKcc20TransferTokenOperation` | Token identity/decimals, display amount, recipient owner, current holder UTXOs. |
|
|
80
|
+
| `mint` | `buildKcc20MintTokenOperation` | Token mint policy, amount, active authority UTXOs, optional recipient. |
|
|
81
|
+
| `mintAvailability` | `buildKcc20MintAvailabilityOperation` | Token, active mint-authority state, requested enabled state. |
|
|
82
|
+
| `consolidate` | `buildKcc20NativeConsolidationOperation` | Token, owner holder UTXOs, optional target amount. |
|
|
83
|
+
| `reveal` | `buildKcc20VerifyTokenOperation` | Token identity and a spendable holder/authority snapshot. |
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const mint = recipes.mint(
|
|
87
|
+
wallet,
|
|
88
|
+
{
|
|
89
|
+
token,
|
|
90
|
+
tokenAmount: "10.00",
|
|
91
|
+
activeUtxos: minterUtxos,
|
|
92
|
+
},
|
|
93
|
+
{ network: "testnet-10" },
|
|
94
|
+
);
|
|
95
|
+
const unsignedMint = await build(mint);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`token` must include its actual decimals and mint policy. Controlled minting
|
|
99
|
+
requires the authority owner. A public mint can be paused. Mint-authority state
|
|
100
|
+
includes extension data that a holder snapshot does not contain. Public mint
|
|
101
|
+
amount limits and paid-mint minimums are validated by the helper.
|
|
102
|
+
|
|
103
|
+
## Wrappers and orderbook
|
|
104
|
+
|
|
105
|
+
| Recipe | Existing helper | Required state |
|
|
106
|
+
| -------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
107
|
+
| `deployMarket` | `buildKcc20WrapperMarketDeployOperation` | Token identity, market configuration and fee-ticket identity if used. |
|
|
108
|
+
| `wrap` | `buildKcc20WrapTokenOperationFromSnapshot` | Native holder, wrapper candidates, native covenant IDs, token decimals and amount. |
|
|
109
|
+
| `unwrap` | `buildKcc20UnwrapTokenOperationFromSnapshot` | Wrapped holder, wrapper reserve, market identity and amount. |
|
|
110
|
+
| `order` | `buildKcc20OrderOperation` | Trading context and buy/sell draft; buy uses a market root, sell uses a wrapped holder. |
|
|
111
|
+
| `fill` | `buildKcc20FillOperation` | Trading context, selected bid/ask, fill amount, funding/holder sources. |
|
|
112
|
+
| `sweep` | `buildKcc20SweepOperation` | Trading context, ordered bid/ask legs and sufficient buyer/seller sources. |
|
|
113
|
+
| `cancel` | `buildKcc20CancelOperation` | Owner's bid/ask and matching market context. |
|
|
114
|
+
| `consolidateWrapped` | `buildKcc20WrappedConsolidationOperation` | Matching wrapped-holder sources and market context. |
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const order = recipes.order(
|
|
118
|
+
wallet,
|
|
119
|
+
tradingContext,
|
|
120
|
+
{
|
|
121
|
+
wrappedMarketId: tradingContext.wrapper.marketId,
|
|
122
|
+
side: "buy",
|
|
123
|
+
tokenAmount: "10.00",
|
|
124
|
+
unitPriceSompi: "100000000",
|
|
125
|
+
},
|
|
126
|
+
{ network: "testnet-10" },
|
|
127
|
+
);
|
|
128
|
+
const unsignedOrder = await build(order);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The context contains token decimals, the wrapper identity and its buildability,
|
|
132
|
+
current wrapped UTXOs, and optional fee-ticket UTXOs. Preserve the distinction
|
|
133
|
+
between native token identity, wrapper identity, and market identity. Use helper
|
|
134
|
+
parameter types rather than constructing a request from UI labels. The bid/ask
|
|
135
|
+
side controls which builder runs and which sources it consumes. Fees, locked
|
|
136
|
+
KAS deposits, price scale, partial-fill change, and token change must be shown
|
|
137
|
+
before signing. Never reuse a quote after its input order has changed.
|
|
138
|
+
|
|
139
|
+
## Fee tickets
|
|
140
|
+
|
|
141
|
+
| Recipe | Existing helper | Required state |
|
|
142
|
+
| --------------------- | ----------------------------------- | ------------------------------------------------------------------------ |
|
|
143
|
+
| `deployFeeTicketRoot` | `buildFeeTicketRootDeployOperation` | Utility token ID, denomination, discount and optional supported markets. |
|
|
144
|
+
| `updateFeeTicketRoot` | `buildFeeTicketRootUpdateOperation` | Root configuration, current root UTXOs and new denomination. |
|
|
145
|
+
| `createFeeTicket` | `buildFeeTicketCreateOperation` | Root configuration, root UTXOs, utility holders and quantity. |
|
|
146
|
+
| `burnFeeTicket` | `buildFeeTicketBurnOperation` | Owner tickets and root configuration. |
|
|
147
|
+
| `transferFeeTicket` | `buildFeeTicketTransferOperation` | Owner tickets, recipient and root configuration. |
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const root = recipes.deployFeeTicketRoot(
|
|
151
|
+
wallet,
|
|
152
|
+
{
|
|
153
|
+
utilityTokenId,
|
|
154
|
+
utilityTokenAmount: "100",
|
|
155
|
+
discountBps: 2500,
|
|
156
|
+
},
|
|
157
|
+
{ network: "testnet-10" },
|
|
158
|
+
);
|
|
159
|
+
const unsignedRoot = await build(root);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`utilityTokenAmount` is an integer denomination in base units. Batch creation
|
|
163
|
+
requires a matching artifact and root capability; use the engine's existing
|
|
164
|
+
`resolveFeeTicketBatchCreateCapability` rather than assuming every root supports
|
|
165
|
+
multiple tickets. Creating tickets burns the selected utility amount.
|
|
166
|
+
|
|
167
|
+
## Backend-only matcher
|
|
168
|
+
|
|
169
|
+
`kcc20orderbook.matcher-settle-crossed` is intentionally excluded from the public
|
|
170
|
+
example registry. The engine accepts it only with `allowBackendOnly: true`.
|
|
171
|
+
Use a separate server instance, validated crossed-order snapshots, and explicit
|
|
172
|
+
operator configuration. Never enable it in the frontend, expose operator
|
|
173
|
+
credentials through a client configuration object, or forward all of `process.env`
|
|
174
|
+
to the engine. Public minting, transfer, and user order actions do not require
|
|
175
|
+
this matcher or KaspaCom's backend.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Build transactions in your application
|
|
2
|
+
|
|
3
|
+
TX Builder constructs transactions locally in a browser or Node process. Your
|
|
4
|
+
application supplies WASM, the packaged contract artifacts, and chain data.
|
|
5
|
+
You do not need KaspaCom's backend to plan or build a transaction.
|
|
6
|
+
|
|
7
|
+
Start with the [runnable examples](../examples/README.md). Both applications use
|
|
8
|
+
[the same construction code](../examples/shared/build.ts) and build a deploy
|
|
9
|
+
followed by a transfer. Their offline transactions are identical across runtimes.
|
|
10
|
+
|
|
11
|
+
## Responsibilities
|
|
12
|
+
|
|
13
|
+
| Part | Responsibility |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| Operation helpers | Validate the requested action, select supplied covenant sources, convert display amounts, and describe intent. |
|
|
16
|
+
| Builder engine | Construct and serialize the funded unsigned transaction, attach covenant bindings, estimate fees, and return signing instructions. |
|
|
17
|
+
| Application | Initialize WASM, load artifacts, retrieve funding UTXOs and decoded covenant state, show transaction intent, and manage RPC lifetime. |
|
|
18
|
+
| Wallet or server signer | Confirm authorization and sign the required inputs, including covenant inputs. |
|
|
19
|
+
| Application and node | Submit the signed transaction, handle rejection, and track acceptance. |
|
|
20
|
+
|
|
21
|
+
A build is neither a signature nor proof of chain acceptance. Source snapshots
|
|
22
|
+
can become stale between construction and submission. On a spent-input failure,
|
|
23
|
+
refresh sources and rebuild; do not keep retrying the same transaction.
|
|
24
|
+
|
|
25
|
+
## Install and initialize
|
|
26
|
+
|
|
27
|
+
Use Node 22 for the examples. The package also supports its declared Node 20+
|
|
28
|
+
range. Install `@kaspacom/kcc20-tx-builder` from the public npm registry; no GitHub
|
|
29
|
+
Packages credentials are needed. Use the release version matching the examples.
|
|
30
|
+
|
|
31
|
+
The host initializes WASM once. See [Node initialization](../examples/backend/runtime.ts)
|
|
32
|
+
and [browser initialization](../examples/frontend/runtime.ts). Both use the
|
|
33
|
+
included ISC-licensed `kaspa-wasm` bundle, version `1.1.1-toc.1`, and call
|
|
34
|
+
`initWASM32Bindings({ validateClassNames: false })`. This allows bindings to work
|
|
35
|
+
when bundlers rename WASM classes. WASM remains host-owned; importing the package
|
|
36
|
+
does not initialize it or open a connection.
|
|
37
|
+
|
|
38
|
+
[COMPATIBILITY.json](COMPATIBILITY.json) pins binary/file checksums, contract
|
|
39
|
+
revision, compiler release, and artifact hashes. The runtime is included under
|
|
40
|
+
`examples/vendor/kaspa` in this repository and package, so neither example
|
|
41
|
+
fetches it from a private repository. The original runtime build's source commit
|
|
42
|
+
is not recorded in the supplied bundle. File integrity is verified; a reproducible
|
|
43
|
+
WASM source build is not claimed. The manifest also supplies an immutable public
|
|
44
|
+
`downloadBaseUrl`. Download `kaspa.js`, `kaspa_bg.wasm`, `kaspa.d.ts`, and
|
|
45
|
+
`LICENSE` from that base and verify each SHA-256 against `wasm.files` if you
|
|
46
|
+
host the runtime separately. Keep the license with redistributed files.
|
|
47
|
+
|
|
48
|
+
## Deploy a fixed-supply token
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { buildKcc20DeployTokenOperation } from '@kaspacom/kcc20-tx-builder/deploy-operation';
|
|
52
|
+
|
|
53
|
+
const operation = buildKcc20DeployTokenOperation(
|
|
54
|
+
wallet, // { walletAddress: 'kaspatest:...', kcc20Owner: '<32-byte x-only public key>' }
|
|
55
|
+
{
|
|
56
|
+
ticker: 'DEMO', tokenName: 'Example token', decimals: 2,
|
|
57
|
+
maxSupply: '1000', premintSupply: '1000',
|
|
58
|
+
mintPolicy: 'fixed', mintPricePerTokenSompi: '0',
|
|
59
|
+
},
|
|
60
|
+
{ network: 'testnet-10' },
|
|
61
|
+
);
|
|
62
|
+
const unsigned = await build(operation);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`build` comes from `createBuilder` in the shared example. That function creates
|
|
66
|
+
one existing `createKcc20PsktBuilderEngine`, verifies packaged artifact hashes,
|
|
67
|
+
and calls its `build` method. The complete adapter is executable code, not an
|
|
68
|
+
unspecified server request.
|
|
69
|
+
|
|
70
|
+
`engineInput(operation)` takes `operation.payload.signing.builderKey`, `params`,
|
|
71
|
+
`owner`, `network`, and source/signer requirements and assembles
|
|
72
|
+
`kcc20-in-process-pskt-builder-input/v1`. The separate shared-model input schema
|
|
73
|
+
is not interchangeable with this engine schema. The helper's
|
|
74
|
+
`missing-funded-pskt` status means construction is still required; historical
|
|
75
|
+
`backend-funded-pskt-builder` labels do not require a KaspaCom backend.
|
|
76
|
+
The local engine performs that construction.
|
|
77
|
+
|
|
78
|
+
The fixed-supply example creates 1,000 tokens with two decimals: 100,000 base
|
|
79
|
+
units. It locks KAS into the token output and returns KAS change to the funding
|
|
80
|
+
wallet. Use decimal strings, not floating-point multiplication, for token
|
|
81
|
+
amounts. KAS amounts and fees are integer sompi; 100,000,000 sompi is one KAS.
|
|
82
|
+
The library's protocol fee defaults still apply to relevant operations; inspect
|
|
83
|
+
the operation and resulting outputs before asking a wallet to sign.
|
|
84
|
+
|
|
85
|
+
## Transfer from a decoded holder snapshot
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { buildKcc20TransferTokenOperation } from '@kaspacom/kcc20-tx-builder/token-operation';
|
|
89
|
+
|
|
90
|
+
const operation = buildKcc20TransferTokenOperation(wallet, {
|
|
91
|
+
token: { covenantId: holder.covenantId, decimals: 2 },
|
|
92
|
+
activeUtxos: [holder],
|
|
93
|
+
recipientOwner, // 32-byte x-only public key, not an address string
|
|
94
|
+
tokenAmount: '12.50',
|
|
95
|
+
}, { network: 'testnet-10' });
|
|
96
|
+
const unsigned = await build(operation);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
See [fixture.ts](../examples/shared/fixture.ts) for a complete holder snapshot:
|
|
100
|
+
transaction ID, output index, address, KAS amount, native covenant ID, owner,
|
|
101
|
+
token amount, extension commitment, and borrow state. The offline fixture derives
|
|
102
|
+
that snapshot from its deploy result. Its outpoints are synthetic and must never
|
|
103
|
+
be used as live funding.
|
|
104
|
+
|
|
105
|
+
Use the [live transfer adapter and walkthrough](LIVE_TRANSFER.md) to retrieve and validate a complete holder snapshot.
|
|
106
|
+
For live use, retrieve decoded state from your own indexer or decode the prior
|
|
107
|
+
transaction and reveal script. RPC UTXOs alone do not contain every contract
|
|
108
|
+
state field. Supply that state to the helper, then let the engine's source
|
|
109
|
+
provider retrieve current RPC entries by address. Preserve the native covenant
|
|
110
|
+
ID from RPC; an application's token identifier or script hash is not always the
|
|
111
|
+
native covenant ID. The engine rebuilds the holder script and checks its address.
|
|
112
|
+
|
|
113
|
+
The example transfers 1,250 base units, retains 98,750 as token change, and
|
|
114
|
+
uses a separate KAS funding input. A fragmented token balance may require
|
|
115
|
+
consolidation first. Funding selection can require one sufficiently large KAS
|
|
116
|
+
UTXO even when the wallet's total balance is sufficient.
|
|
117
|
+
|
|
118
|
+
## Inspect, sign, submit
|
|
119
|
+
|
|
120
|
+
The engine returns `psktTransactionJson`, `signInputs`, optional `scripts`,
|
|
121
|
+
`metadata`, and `submitTransactionSupported`. Inspect the full transaction,
|
|
122
|
+
recipients, token change, covenant IDs, KAS change, and fee before signing.
|
|
123
|
+
`inspect` computes the fee from input amounts minus output values.
|
|
124
|
+
|
|
125
|
+
[The signing adapter](../examples/shared/signing.ts) includes the covenant input
|
|
126
|
+
indexes from `scripts` as well as ordinary `signInputs`. After KasWare signs,
|
|
127
|
+
it inserts the signature into the ordered ABI arguments and wraps the redeem
|
|
128
|
+
script. Omitting this step produces a signed funding input but an invalid
|
|
129
|
+
covenant spend. Preserve every builder-provided sighash and script template. The adapter preserves
|
|
130
|
+
prebuilt witnesses on inputs the wallet does not sign, checks returned signature
|
|
131
|
+
encoding and sighash bytes, and rejects changes to transaction intent. These
|
|
132
|
+
checks do not replace cryptographic verification or node consensus validation.
|
|
133
|
+
When using the WASM signer directly, map wire sighash `1` to `wasm.SighashType.All`;
|
|
134
|
+
the WASM enum's numeric value is `0`, not the wire byte.
|
|
135
|
+
|
|
136
|
+
The frontend checks the wallet account and TN10 network, then offers separate
|
|
137
|
+
Sign and Broadcast actions. It submits through the selected RPC node. The backend
|
|
138
|
+
example returns an unsigned transaction for an application or wallet to sign;
|
|
139
|
+
it does not load private keys. The offline suite verifies construction and
|
|
140
|
+
script assembly, not a wallet extension's current behavior or live acceptance.
|
|
141
|
+
|
|
142
|
+
For server integrations, call the same shared `createBuilder` function from your
|
|
143
|
+
handler with a process-owned RPC connection. Validate the caller's request and
|
|
144
|
+
apply your own authorization before signing. Return the builder result as JSON;
|
|
145
|
+
never forward your environment or signing credentials to a browser.
|
|
146
|
+
|
|
147
|
+
## Failure handling
|
|
148
|
+
|
|
149
|
+
| Failure | Application action |
|
|
150
|
+
| --- | --- |
|
|
151
|
+
| Insufficient KAS or no single funding UTXO | Refresh funding and obtain an adequate input; inspect the required output deposits and fee. |
|
|
152
|
+
| No holder large enough | Check ownership and decimals; consolidate if the balance is fragmented. |
|
|
153
|
+
| Active holder not found | Refresh decoded state and RPC UTXOs; the input may have been spent. |
|
|
154
|
+
| Rebuilt script address mismatch | Check decoded state and artifact version; do not substitute another address. |
|
|
155
|
+
| Artifact hash mismatch | Use the artifacts shipped with this package version. |
|
|
156
|
+
| Wrong network or missing WASM capability | Correct host configuration before building. |
|
|
157
|
+
| Wallet rejection | Keep the transaction unsigned and report cancellation. |
|
|
158
|
+
| Node rejection or uncertain submission | Query acceptance and spent inputs before rebuilding or retrying. |
|
|
159
|
+
|
|
160
|
+
Errors include both plain `Error` messages and structured builder errors. Do not
|
|
161
|
+
assume every error has a `code`. Add transport timeouts appropriate to your host,
|
|
162
|
+
and close failed connections. Browser applications should reuse one RPC
|
|
163
|
+
connection rather than reconnecting for each build.
|