@1sat/actions 0.0.230 → 0.0.232
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apply/opnsRegister.d.ts +12 -5
- package/dist/apply/opnsRegister.d.ts.map +1 -1
- package/dist/apply/opnsRegister.js +68 -10
- package/dist/apply/opnsRegister.js.map +1 -1
- package/dist/funding/index.d.ts +1 -0
- package/dist/funding/index.d.ts.map +1 -1
- package/dist/funding/index.js +1 -1
- package/dist/funding/index.js.map +1 -1
- package/dist/funding/walletFunding.d.ts +47 -0
- package/dist/funding/walletFunding.d.ts.map +1 -0
- package/dist/funding/walletFunding.js +162 -0
- package/dist/funding/walletFunding.js.map +1 -0
- package/dist/funding/walletFunding.test.d.ts +2 -0
- package/dist/funding/walletFunding.test.d.ts.map +1 -0
- package/dist/funding/walletFunding.test.js +225 -0
- package/dist/funding/walletFunding.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/mandala/deploy.d.ts +89 -0
- package/dist/mandala/deploy.d.ts.map +1 -0
- package/dist/mandala/deploy.js +226 -0
- package/dist/mandala/deploy.js.map +1 -0
- package/dist/mandala/deploy.test.d.ts +2 -0
- package/dist/mandala/deploy.test.d.ts.map +1 -0
- package/dist/mandala/deploy.test.js +281 -0
- package/dist/mandala/deploy.test.js.map +1 -0
- package/dist/mandala/index.d.ts +9 -0
- package/dist/mandala/index.d.ts.map +1 -0
- package/dist/mandala/index.js +17 -0
- package/dist/mandala/index.js.map +1 -0
- package/dist/mandala/receive.d.ts +58 -0
- package/dist/mandala/receive.d.ts.map +1 -0
- package/dist/mandala/receive.js +162 -0
- package/dist/mandala/receive.js.map +1 -0
- package/dist/mandala/send.d.ts +74 -0
- package/dist/mandala/send.d.ts.map +1 -0
- package/dist/mandala/send.js +313 -0
- package/dist/mandala/send.js.map +1 -0
- package/dist/mandala/send.test.d.ts +2 -0
- package/dist/mandala/send.test.d.ts.map +1 -0
- package/dist/mandala/send.test.js +515 -0
- package/dist/mandala/send.test.js.map +1 -0
- package/dist/mandala/tokenId.d.ts +21 -0
- package/dist/mandala/tokenId.d.ts.map +1 -0
- package/dist/mandala/tokenId.js +29 -0
- package/dist/mandala/tokenId.js.map +1 -0
- package/dist/metanet/brc78.d.ts +29 -0
- package/dist/metanet/brc78.d.ts.map +1 -0
- package/dist/metanet/brc78.js +60 -0
- package/dist/metanet/brc78.js.map +1 -0
- package/dist/metanet/deliver.d.ts +26 -0
- package/dist/metanet/deliver.d.ts.map +1 -0
- package/dist/metanet/deliver.js +34 -0
- package/dist/metanet/deliver.js.map +1 -0
- package/dist/metanet/envelope.d.ts +69 -0
- package/dist/metanet/envelope.d.ts.map +1 -0
- package/dist/metanet/envelope.js +86 -0
- package/dist/metanet/envelope.js.map +1 -0
- package/dist/metanet/envelope.test.d.ts +2 -0
- package/dist/metanet/envelope.test.d.ts.map +1 -0
- package/dist/metanet/envelope.test.js +106 -0
- package/dist/metanet/envelope.test.js.map +1 -0
- package/dist/metanet/inbox.d.ts +51 -0
- package/dist/metanet/inbox.d.ts.map +1 -0
- package/dist/metanet/inbox.js +100 -0
- package/dist/metanet/inbox.js.map +1 -0
- package/dist/metanet/index.d.ts +8 -0
- package/dist/metanet/index.d.ts.map +1 -0
- package/dist/metanet/index.js +9 -0
- package/dist/metanet/index.js.map +1 -0
- package/dist/metanet/receive.d.ts +50 -0
- package/dist/metanet/receive.d.ts.map +1 -0
- package/dist/metanet/receive.js +107 -0
- package/dist/metanet/receive.js.map +1 -0
- package/dist/metanet/relay.d.ts +37 -0
- package/dist/metanet/relay.d.ts.map +1 -0
- package/dist/metanet/relay.js +51 -0
- package/dist/metanet/relay.js.map +1 -0
- package/dist/opns/index.d.ts +65 -4
- package/dist/opns/index.d.ts.map +1 -1
- package/dist/opns/index.js +93 -34
- package/dist/opns/index.js.map +1 -1
- package/dist/opns/registerOpns.test.d.ts +2 -0
- package/dist/opns/registerOpns.test.d.ts.map +1 -0
- package/dist/opns/registerOpns.test.js +186 -0
- package/dist/opns/registerOpns.test.js.map +1 -0
- package/dist/payments/index.d.ts +32 -1
- package/dist/payments/index.d.ts.map +1 -1
- package/dist/payments/index.js +118 -6
- package/dist/payments/index.js.map +1 -1
- package/dist/payments/sendBsvHandle.test.d.ts +2 -0
- package/dist/payments/sendBsvHandle.test.d.ts.map +1 -0
- package/dist/payments/sendBsvHandle.test.js +478 -0
- package/dist/payments/sendBsvHandle.test.js.map +1 -0
- package/package.json +8 -7
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { type CreateActionArgs, type WalletInterface } from '@bsv/sdk';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* Put the real signature into an `opns.register` draft lock. The action emits
|
|
4
|
+
* the complete script — `<lock pubkey> CHECKSIG`, the key/value fields
|
|
5
|
+
* (`identity`, `profile`, …), a zero-filled signature push, the drops, and
|
|
6
|
+
* optionally an inscription envelope. Apply signs the fields and replaces the
|
|
7
|
+
* placeholder push (chunk `2 + fieldCount`) with the signature push; nothing
|
|
8
|
+
* else in the script changes. The DER signature may be shorter than the
|
|
9
|
+
* placeholder, so the push is re-encoded with its own length.
|
|
10
|
+
*
|
|
11
|
+
* The lock pubkey in the draft must be this wallet's key for the publish
|
|
12
|
+
* keyID, and the fields are checked before signing so only a well-formed
|
|
13
|
+
* publish (exactly one `identity` pair) is ever signed. Uses the given wallet
|
|
14
|
+
* (must be base — never a gated WPM wrapper).
|
|
8
15
|
*/
|
|
9
16
|
export declare function applyOpnsRegister(wallet: WalletInterface, args: CreateActionArgs): Promise<void>;
|
|
10
17
|
//# sourceMappingURL=opnsRegister.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opnsRegister.d.ts","sourceRoot":"","sources":["../../src/apply/opnsRegister.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"opnsRegister.d.ts","sourceRoot":"","sources":["../../src/apply/opnsRegister.ts"],"names":[],"mappings":"AASA,OAAO,EACN,KAAK,gBAAgB,EAErB,KAAK,eAAe,EACpB,MAAM,UAAU,CAAA;AA6BjB;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,gBAAgB,GACpB,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
|
@@ -1,11 +1,44 @@
|
|
|
1
|
-
import { OPNS_BASKET, OPNS_REGISTER_COUNTERPARTY, P1SAT_PROTOCOL, opnsRegisterKeyId, } from '@1sat/types';
|
|
2
|
-
import {
|
|
1
|
+
import { IDENTITY_FIELD, OPNS_BASKET, OPNS_REGISTER_COUNTERPARTY, P1SAT_PROTOCOL, PROFILE_FIELD, opnsRegisterKeyId, } from '@1sat/types';
|
|
2
|
+
import { decodeProfile, fieldPairs, isIdentityKey } from '@1sat/utils';
|
|
3
|
+
import { LockingScript, } from '@bsv/sdk';
|
|
4
|
+
import { pushDropDecode } from '../utils/pushdrop.js';
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
* Check the key/value fields before signing them: exactly one `identity`
|
|
7
|
+
* (33-byte compressed key), at most one `profile` (valid DAG-CBOR profile).
|
|
8
|
+
* Unknown keys are allowed.
|
|
9
|
+
*/
|
|
10
|
+
function assertPublishFields(fields) {
|
|
11
|
+
let identities = 0;
|
|
12
|
+
let profiles = 0;
|
|
13
|
+
for (const [key, value] of fieldPairs(fields)) {
|
|
14
|
+
if (key === IDENTITY_FIELD) {
|
|
15
|
+
if (!isIdentityKey(value)) {
|
|
16
|
+
throw new Error('opns.register apply: identity is not a compressed key');
|
|
17
|
+
}
|
|
18
|
+
identities++;
|
|
19
|
+
}
|
|
20
|
+
else if (key === PROFILE_FIELD) {
|
|
21
|
+
decodeProfile(value);
|
|
22
|
+
profiles++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (identities !== 1 || profiles > 1) {
|
|
26
|
+
throw new Error('opns.register apply: fields need exactly one identity and at most one profile');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Put the real signature into an `opns.register` draft lock. The action emits
|
|
31
|
+
* the complete script — `<lock pubkey> CHECKSIG`, the key/value fields
|
|
32
|
+
* (`identity`, `profile`, …), a zero-filled signature push, the drops, and
|
|
33
|
+
* optionally an inscription envelope. Apply signs the fields and replaces the
|
|
34
|
+
* placeholder push (chunk `2 + fieldCount`) with the signature push; nothing
|
|
35
|
+
* else in the script changes. The DER signature may be shorter than the
|
|
36
|
+
* placeholder, so the push is re-encoded with its own length.
|
|
37
|
+
*
|
|
38
|
+
* The lock pubkey in the draft must be this wallet's key for the publish
|
|
39
|
+
* keyID, and the fields are checked before signing so only a well-formed
|
|
40
|
+
* publish (exactly one `identity` pair) is ever signed. Uses the given wallet
|
|
41
|
+
* (must be base — never a gated WPM wrapper).
|
|
9
42
|
*/
|
|
10
43
|
export async function applyOpnsRegister(wallet, args) {
|
|
11
44
|
const outputs = args.outputs;
|
|
@@ -22,12 +55,37 @@ export async function applyOpnsRegister(wallet, args) {
|
|
|
22
55
|
if (!input?.outpoint) {
|
|
23
56
|
throw new Error('opns.register apply: missing input outpoint');
|
|
24
57
|
}
|
|
25
|
-
const
|
|
58
|
+
const draft = LockingScript.fromHex(out.lockingScript);
|
|
59
|
+
const decoded = pushDropDecode(draft);
|
|
60
|
+
const fields = decoded.fields.map((f) => [...f]);
|
|
26
61
|
const placeholder = fields.pop();
|
|
27
62
|
if (!placeholder?.length || placeholder.some((b) => b !== 0)) {
|
|
28
63
|
throw new Error('opns.register apply: signature field is not zeroed');
|
|
29
64
|
}
|
|
30
|
-
|
|
31
|
-
|
|
65
|
+
assertPublishFields(fields);
|
|
66
|
+
const keyID = opnsRegisterKeyId(input.outpoint);
|
|
67
|
+
const { publicKey } = await wallet.getPublicKey({
|
|
68
|
+
protocolID: P1SAT_PROTOCOL,
|
|
69
|
+
keyID,
|
|
70
|
+
counterparty: OPNS_REGISTER_COUNTERPARTY,
|
|
71
|
+
forSelf: true,
|
|
72
|
+
});
|
|
73
|
+
if (publicKey !== decoded.lockingPublicKey.toString()) {
|
|
74
|
+
throw new Error('opns.register apply: lock key does not match keyID');
|
|
75
|
+
}
|
|
76
|
+
const { signature } = await wallet.createSignature({
|
|
77
|
+
data: fields.flat(),
|
|
78
|
+
protocolID: P1SAT_PROTOCOL,
|
|
79
|
+
keyID,
|
|
80
|
+
counterparty: OPNS_REGISTER_COUNTERPARTY,
|
|
81
|
+
});
|
|
82
|
+
// Signatures are 70–72 bytes: always a direct push (opcode = length).
|
|
83
|
+
const chunks = [...draft.chunks];
|
|
84
|
+
const at = 2 + fields.length;
|
|
85
|
+
if (chunks[at]?.data?.length !== placeholder.length) {
|
|
86
|
+
throw new Error('opns.register apply: placeholder push not found');
|
|
87
|
+
}
|
|
88
|
+
chunks[at] = { op: signature.length, data: signature };
|
|
89
|
+
out.lockingScript = new LockingScript(chunks).toHex();
|
|
32
90
|
}
|
|
33
91
|
//# sourceMappingURL=opnsRegister.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opnsRegister.js","sourceRoot":"","sources":["../../src/apply/opnsRegister.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,WAAW,EACX,0BAA0B,EAC1B,cAAc,EACd,iBAAiB,GACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAEN,aAAa,
|
|
1
|
+
{"version":3,"file":"opnsRegister.js","sourceRoot":"","sources":["../../src/apply/opnsRegister.ts"],"names":[],"mappings":"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"}
|
package/dist/funding/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/funding/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAE5D;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,UAAU,CAAA;CACd"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/funding/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAE5D;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,UAAU,CAAA;CACd;AAED,OAAO,EACN,2BAA2B,EAC3B,cAAc,EACd,KAAK,4BAA4B,GACjC,MAAM,oBAAoB,CAAA"}
|
package/dist/funding/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {};
|
|
1
|
+
export { createWalletFundingProvider, FUNDING_BASKET, } from './walletFunding.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/funding/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/funding/index.ts"],"names":[],"mappings":"AA2BA,OAAO,EACN,2BAA2B,EAC3B,cAAc,GAEd,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type AtomicBEEF, Transaction } from '@bsv/sdk';
|
|
2
|
+
import type { OneSatContext } from '../types.js';
|
|
3
|
+
import type { FundingProvider } from './index.js';
|
|
4
|
+
/** The SDK's fee model interface (not exported by `@bsv/sdk` by name). */
|
|
5
|
+
type FeeModel = Exclude<Parameters<Transaction['fee']>[0], number | undefined>;
|
|
6
|
+
/** Basket the wallet files side-door funding UTXOs into. */
|
|
7
|
+
export declare const FUNDING_BASKET = "funding";
|
|
8
|
+
export interface WalletFundingProviderOptions {
|
|
9
|
+
/** Fee model for the target transaction. Default: the SDK's `LivePolicy`. */
|
|
10
|
+
feeModel?: FeeModel;
|
|
11
|
+
/** Basket for the funding UTXO. Default {@link FUNDING_BASKET}. */
|
|
12
|
+
basket?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Broadcast step for the signed target transaction. Resolve on success,
|
|
15
|
+
* throw otherwise. Default: `ctx.services.postBeef`.
|
|
16
|
+
*/
|
|
17
|
+
broadcast?: (beef: AtomicBEEF, txid: string) => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A {@link FundingProvider} that pays from the caller's own wallet through a
|
|
21
|
+
* side door, so the target transaction can be internalized afterwards with
|
|
22
|
+
* tags that depend on its txid.
|
|
23
|
+
*
|
|
24
|
+
* 1. `createAction` one P2PKH funding UTXO to a wallet-derived key, sized to
|
|
25
|
+
* the target's outputs plus its fee (normal broadcast), filed in
|
|
26
|
+
* {@link FUNDING_BASKET} with the derivation in customInstructions.
|
|
27
|
+
* 2. Build the target transaction: the caller's inputs in the caller's order,
|
|
28
|
+
* each with its unlocking script verbatim and its source transaction from
|
|
29
|
+
* `args.inputBEEF`, then that UTXO appended as the last input, signed with
|
|
30
|
+
* `getPublicKey` / `createSignature` for the stored derivation; the
|
|
31
|
+
* caller's outputs in the caller's order. The UTXO is sized exactly, so
|
|
32
|
+
* there is no change output.
|
|
33
|
+
* 3. Broadcast it with `options.broadcast` (default `ctx.services.postBeef`).
|
|
34
|
+
* 4. Return `{ txid, tx: AtomicBEEF }`.
|
|
35
|
+
*
|
|
36
|
+
* Not used by `deployMandala` (which is one createAction + one
|
|
37
|
+
* internalizeAction); kept as a reusable provider.
|
|
38
|
+
*
|
|
39
|
+
* Caller inputs must already carry their unlocking script, signed so the
|
|
40
|
+
* appended funding input does not invalidate it (`SIGHASH_ALL |
|
|
41
|
+
* ANYONECANPAY`); scripts are not re-signed or checked. An input with only
|
|
42
|
+
* `unlockingScriptLength` throws `wallet-funding-input-unsigned`: this
|
|
43
|
+
* provider cannot sign for the caller.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createWalletFundingProvider(ctx: OneSatContext, options?: WalletFundingProviderOptions): FundingProvider;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=walletFunding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walletFunding.d.ts","sourceRoot":"","sources":["../../src/funding/walletFunding.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,UAAU,EAMf,WAAW,EAIX,MAAM,UAAU,CAAA;AAEjB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAIhD,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAA;AAEhE,0EAA0E;AAC1E,KAAK,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAE9E,4DAA4D;AAC5D,eAAO,MAAM,cAAc,YAAY,CAAA;AAUvC,MAAM,WAAW,4BAA4B;IAC5C,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,4BAAiC,GACxC,eAAe,CA8EjB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { parseOutpoint } from '@1sat/utils';
|
|
2
|
+
import { Beef, LivePolicy, LockingScript, Transaction, UnlockingScript, } from '@bsv/sdk';
|
|
3
|
+
import { P1SAT_PROTOCOL } from '../constants.js';
|
|
4
|
+
import { executeTrackedAction } from '../utils/createTrackedAction.js';
|
|
5
|
+
import { resolveDestination } from '../utils/resolveDestination.js';
|
|
6
|
+
import { signP2PKHInput } from '../utils/signP2PKH.js';
|
|
7
|
+
/** Basket the wallet files side-door funding UTXOs into. */
|
|
8
|
+
export const FUNDING_BASKET = 'funding';
|
|
9
|
+
/**
|
|
10
|
+
* Maximum P2PKH unlocking script length, used for fee sizing so the funding
|
|
11
|
+
* UTXO never under-pays: push opcode (1) + DER signature at most 72 bytes +
|
|
12
|
+
* sighash byte (1) + push opcode (1) + compressed pubkey (33) = 108 bytes.
|
|
13
|
+
* A shorter real signature over-pays by a byte or two.
|
|
14
|
+
*/
|
|
15
|
+
const P2PKH_UNLOCK_LENGTH = 108;
|
|
16
|
+
/**
|
|
17
|
+
* A {@link FundingProvider} that pays from the caller's own wallet through a
|
|
18
|
+
* side door, so the target transaction can be internalized afterwards with
|
|
19
|
+
* tags that depend on its txid.
|
|
20
|
+
*
|
|
21
|
+
* 1. `createAction` one P2PKH funding UTXO to a wallet-derived key, sized to
|
|
22
|
+
* the target's outputs plus its fee (normal broadcast), filed in
|
|
23
|
+
* {@link FUNDING_BASKET} with the derivation in customInstructions.
|
|
24
|
+
* 2. Build the target transaction: the caller's inputs in the caller's order,
|
|
25
|
+
* each with its unlocking script verbatim and its source transaction from
|
|
26
|
+
* `args.inputBEEF`, then that UTXO appended as the last input, signed with
|
|
27
|
+
* `getPublicKey` / `createSignature` for the stored derivation; the
|
|
28
|
+
* caller's outputs in the caller's order. The UTXO is sized exactly, so
|
|
29
|
+
* there is no change output.
|
|
30
|
+
* 3. Broadcast it with `options.broadcast` (default `ctx.services.postBeef`).
|
|
31
|
+
* 4. Return `{ txid, tx: AtomicBEEF }`.
|
|
32
|
+
*
|
|
33
|
+
* Not used by `deployMandala` (which is one createAction + one
|
|
34
|
+
* internalizeAction); kept as a reusable provider.
|
|
35
|
+
*
|
|
36
|
+
* Caller inputs must already carry their unlocking script, signed so the
|
|
37
|
+
* appended funding input does not invalidate it (`SIGHASH_ALL |
|
|
38
|
+
* ANYONECANPAY`); scripts are not re-signed or checked. An input with only
|
|
39
|
+
* `unlockingScriptLength` throws `wallet-funding-input-unsigned`: this
|
|
40
|
+
* provider cannot sign for the caller.
|
|
41
|
+
*/
|
|
42
|
+
export function createWalletFundingProvider(ctx, options = {}) {
|
|
43
|
+
const feeModel = options.feeModel ?? LivePolicy.getInstance();
|
|
44
|
+
const basket = options.basket ?? FUNDING_BASKET;
|
|
45
|
+
const broadcast = options.broadcast ??
|
|
46
|
+
(async (beef, txid) => {
|
|
47
|
+
if (!ctx.services)
|
|
48
|
+
throw new Error('services-required');
|
|
49
|
+
const [result] = await ctx.services.postBeef(Beef.fromBinary(beef), [
|
|
50
|
+
txid,
|
|
51
|
+
]);
|
|
52
|
+
if (result?.status !== 'success') {
|
|
53
|
+
throw new Error(result?.error?.message ?? 'no result');
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
async fund(args) {
|
|
58
|
+
if (!options.broadcast && !ctx.services) {
|
|
59
|
+
throw new Error('services-required');
|
|
60
|
+
}
|
|
61
|
+
const callerInputs = callerTransactionInputs(args);
|
|
62
|
+
const outputs = args.outputs ?? [];
|
|
63
|
+
const funding = await resolveDestination(ctx, undefined, {
|
|
64
|
+
protocolID: P1SAT_PROTOCOL,
|
|
65
|
+
keyIDPrefix: 'funding',
|
|
66
|
+
});
|
|
67
|
+
const derivation = funding.customInstructions;
|
|
68
|
+
if (!derivation)
|
|
69
|
+
throw new Error('funding-derivation-missing');
|
|
70
|
+
const unlock = walletP2PKHUnlock(ctx, derivation.protocolID, derivation.keyID);
|
|
71
|
+
// Size the fee on the target's final shape, before the input exists.
|
|
72
|
+
const draft = targetTransaction(callerInputs, outputs, unlock, {
|
|
73
|
+
sourceTXID: '00'.repeat(32),
|
|
74
|
+
sourceOutputIndex: 0,
|
|
75
|
+
});
|
|
76
|
+
const fee = await feeModel.computeFee(draft);
|
|
77
|
+
const fundingSats = outputs.reduce((sum, o) => sum + o.satoshis, 0) + fee;
|
|
78
|
+
const funded = await executeTrackedAction(ctx.wallet, {
|
|
79
|
+
description: 'Fund side-door transaction',
|
|
80
|
+
outputs: [
|
|
81
|
+
{
|
|
82
|
+
lockingScript: funding.lockingScript.toHex(),
|
|
83
|
+
satoshis: fundingSats,
|
|
84
|
+
outputDescription: 'Side-door funding',
|
|
85
|
+
basket,
|
|
86
|
+
customInstructions: JSON.stringify(derivation),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
options: { randomizeOutputs: false },
|
|
90
|
+
});
|
|
91
|
+
if (funded.error)
|
|
92
|
+
throw new Error(funded.error);
|
|
93
|
+
if (!funded.tx)
|
|
94
|
+
throw new Error('funding-no-tx');
|
|
95
|
+
const fundingTx = Transaction.fromAtomicBEEF(funded.tx);
|
|
96
|
+
const tx = targetTransaction(callerInputs, outputs, unlock, {
|
|
97
|
+
sourceTransaction: fundingTx,
|
|
98
|
+
sourceOutputIndex: 0,
|
|
99
|
+
});
|
|
100
|
+
await tx.sign();
|
|
101
|
+
const txid = tx.id('hex');
|
|
102
|
+
const beef = tx.toAtomicBEEF();
|
|
103
|
+
try {
|
|
104
|
+
await broadcast(beef, txid);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
throw new Error(`funding-broadcast-failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
108
|
+
}
|
|
109
|
+
return { txid, tx: beef };
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** The caller's signed inputs, in order, sourced from `args.inputBEEF`. */
|
|
114
|
+
function callerTransactionInputs(args) {
|
|
115
|
+
const inputs = args.inputs ?? [];
|
|
116
|
+
const beef = inputs.length && args.inputBEEF
|
|
117
|
+
? Beef.fromBinary(args.inputBEEF)
|
|
118
|
+
: undefined;
|
|
119
|
+
return inputs.map((input) => {
|
|
120
|
+
if (input.unlockingScript === undefined) {
|
|
121
|
+
throw new Error('wallet-funding-input-unsigned');
|
|
122
|
+
}
|
|
123
|
+
const { txid, vout } = parseOutpoint(input.outpoint);
|
|
124
|
+
const sourceTransaction = beef?.findTxid(txid)?.tx;
|
|
125
|
+
return {
|
|
126
|
+
...(sourceTransaction ? { sourceTransaction } : { sourceTXID: txid }),
|
|
127
|
+
sourceOutputIndex: vout,
|
|
128
|
+
unlockingScript: UnlockingScript.fromHex(input.unlockingScript),
|
|
129
|
+
sequence: input.sequenceNumber ?? 0xffffffff,
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function targetTransaction(callerInputs, outputs, unlock, source) {
|
|
134
|
+
const tx = new Transaction();
|
|
135
|
+
for (const input of callerInputs)
|
|
136
|
+
tx.addInput({ ...input });
|
|
137
|
+
tx.addInput({
|
|
138
|
+
...source,
|
|
139
|
+
unlockingScriptTemplate: unlock,
|
|
140
|
+
sequence: 0xffffffff,
|
|
141
|
+
});
|
|
142
|
+
for (const o of outputs) {
|
|
143
|
+
tx.addOutput({
|
|
144
|
+
lockingScript: LockingScript.fromHex(o.lockingScript),
|
|
145
|
+
satoshis: o.satoshis,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return tx;
|
|
149
|
+
}
|
|
150
|
+
/** Unlocking template over {@link signP2PKHInput} (wallet-held derived key). */
|
|
151
|
+
function walletP2PKHUnlock(ctx, protocolID, keyID) {
|
|
152
|
+
return {
|
|
153
|
+
sign: async (tx, inputIndex) => {
|
|
154
|
+
const hex = await signP2PKHInput(ctx, tx, inputIndex, protocolID, keyID);
|
|
155
|
+
if (typeof hex !== 'string')
|
|
156
|
+
throw new Error(hex.error);
|
|
157
|
+
return UnlockingScript.fromHex(hex);
|
|
158
|
+
},
|
|
159
|
+
estimateLength: async () => P2PKH_UNLOCK_LENGTH,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=walletFunding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walletFunding.js","sourceRoot":"","sources":["../../src/funding/walletFunding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walletFunding.test.d.ts","sourceRoot":"","sources":["../../src/funding/walletFunding.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { LockingScript, MerklePath, P2PKH, PrivateKey, ProtoWallet, PublicKey, SatoshisPerKilobyte, Spend, Transaction, UnlockingScript, } from '@bsv/sdk';
|
|
3
|
+
import { FUNDING_BASKET, createWalletFundingProvider } from './walletFunding.js';
|
|
4
|
+
const feeModel = new SatoshisPerKilobyte(100);
|
|
5
|
+
const proto = new ProtoWallet(PrivateKey.fromHex('01'.repeat(32)));
|
|
6
|
+
const lockA = new P2PKH().lock(PrivateKey.fromHex('02'.repeat(32)).toPublicKey().toAddress());
|
|
7
|
+
const lockB = new P2PKH().lock(PrivateKey.fromHex('03'.repeat(32)).toPublicKey().toAddress());
|
|
8
|
+
/** A mined parent so AtomicBEEF can terminate in a proof. */
|
|
9
|
+
function minedParent(lock = lockA) {
|
|
10
|
+
const parent = new Transaction();
|
|
11
|
+
parent.addInput({
|
|
12
|
+
sourceTXID: '11'.repeat(32),
|
|
13
|
+
sourceOutputIndex: 0,
|
|
14
|
+
unlockingScript: new UnlockingScript(),
|
|
15
|
+
sequence: 0xffffffff,
|
|
16
|
+
});
|
|
17
|
+
parent.addOutput({ lockingScript: lock, satoshis: 1_000_000 });
|
|
18
|
+
parent.merklePath = new MerklePath(100, [
|
|
19
|
+
[{ offset: 0, hash: parent.id('hex'), txid: true }],
|
|
20
|
+
]);
|
|
21
|
+
return parent;
|
|
22
|
+
}
|
|
23
|
+
function fakeContext(opts = {}) {
|
|
24
|
+
const created = [];
|
|
25
|
+
const posted = [];
|
|
26
|
+
const wallet = {
|
|
27
|
+
getPublicKey: (a) => proto.getPublicKey(a),
|
|
28
|
+
createSignature: (a) => proto.createSignature(a),
|
|
29
|
+
createAction: async (args) => {
|
|
30
|
+
created.push(args);
|
|
31
|
+
const parent = minedParent();
|
|
32
|
+
const tx = new Transaction();
|
|
33
|
+
tx.addInput({
|
|
34
|
+
sourceTransaction: parent,
|
|
35
|
+
sourceOutputIndex: 0,
|
|
36
|
+
unlockingScript: new UnlockingScript(),
|
|
37
|
+
sequence: 0xffffffff,
|
|
38
|
+
});
|
|
39
|
+
for (const o of args.outputs ?? []) {
|
|
40
|
+
tx.addOutput({
|
|
41
|
+
lockingScript: LockingScript.fromHex(o.lockingScript),
|
|
42
|
+
satoshis: o.satoshis,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return { txid: tx.id('hex'), tx: tx.toAtomicBEEF() };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
const ctx = {
|
|
49
|
+
wallet: wallet,
|
|
50
|
+
chain: 'main',
|
|
51
|
+
isBaseWallet: true,
|
|
52
|
+
services: {
|
|
53
|
+
postBeef: async (beef, txids) => {
|
|
54
|
+
posted.push({ beef, txids });
|
|
55
|
+
return [
|
|
56
|
+
opts.broadcast === 'error'
|
|
57
|
+
? {
|
|
58
|
+
name: 'fake',
|
|
59
|
+
status: 'error',
|
|
60
|
+
error: new Error('REJECTED'),
|
|
61
|
+
txidResults: [],
|
|
62
|
+
}
|
|
63
|
+
: {
|
|
64
|
+
name: 'fake',
|
|
65
|
+
status: 'success',
|
|
66
|
+
txidResults: [{ txid: txids[0], status: 'success' }],
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
return { ctx, created, posted };
|
|
73
|
+
}
|
|
74
|
+
const targetArgs = () => ({
|
|
75
|
+
description: 'Target transaction',
|
|
76
|
+
outputs: [
|
|
77
|
+
{ lockingScript: lockA.toHex(), satoshis: 1, outputDescription: 'a' },
|
|
78
|
+
{ lockingScript: lockB.toHex(), satoshis: 546, outputDescription: 'b' },
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
describe('createWalletFundingProvider', () => {
|
|
82
|
+
test('funds, builds in caller order, signs, broadcasts, returns AtomicBEEF', async () => {
|
|
83
|
+
const { ctx, created, posted } = fakeContext();
|
|
84
|
+
const provider = createWalletFundingProvider(ctx, { feeModel });
|
|
85
|
+
const args = targetArgs();
|
|
86
|
+
const { txid, tx: beef } = await provider.fund(args);
|
|
87
|
+
// (a) one funding UTXO, P2PKH to a wallet-derived key, filed with its derivation
|
|
88
|
+
expect(created).toHaveLength(1);
|
|
89
|
+
const fundOut = created[0].outputs?.[0];
|
|
90
|
+
expect(created[0].outputs).toHaveLength(1);
|
|
91
|
+
expect(fundOut?.basket).toBe(FUNDING_BASKET);
|
|
92
|
+
const ci = JSON.parse(fundOut?.customInstructions ?? '{}');
|
|
93
|
+
expect(ci.protocolID).toBeDefined();
|
|
94
|
+
expect(ci.keyID).toStartWith('funding-');
|
|
95
|
+
const { publicKey } = await proto.getPublicKey({
|
|
96
|
+
protocolID: ci.protocolID,
|
|
97
|
+
keyID: ci.keyID,
|
|
98
|
+
counterparty: 'self',
|
|
99
|
+
forSelf: true,
|
|
100
|
+
});
|
|
101
|
+
expect(fundOut?.lockingScript).toBe(new P2PKH().lock(PublicKey.fromString(publicKey).toAddress()).toHex());
|
|
102
|
+
// (b) target: the funding UTXO in, caller outputs in caller order, no change
|
|
103
|
+
const tx = Transaction.fromAtomicBEEF(beef);
|
|
104
|
+
expect(tx.id('hex')).toBe(txid);
|
|
105
|
+
expect(tx.inputs).toHaveLength(1);
|
|
106
|
+
const fundingTx = tx.inputs[0].sourceTransaction;
|
|
107
|
+
expect(fundingTx.outputs[0].lockingScript.toHex()).toBe(fundOut?.lockingScript);
|
|
108
|
+
expect(tx.outputs.map((o) => [o.lockingScript.toHex(), o.satoshis])).toEqual((args.outputs ?? []).map((o) => [o.lockingScript, o.satoshis]));
|
|
109
|
+
// fee: funding = outputs + the model's fee at the maximum unlock length
|
|
110
|
+
const paid = (fundOut?.satoshis ?? 0) - 547;
|
|
111
|
+
expect(paid).toBeGreaterThan(0);
|
|
112
|
+
// sized at the maximum unlock length: never under-pays the signed tx
|
|
113
|
+
expect(paid).toBeGreaterThanOrEqual(await feeModel.computeFee(tx));
|
|
114
|
+
// signed with the derived key
|
|
115
|
+
const input = tx.inputs[0];
|
|
116
|
+
const spend = new Spend({
|
|
117
|
+
sourceTXID: fundingTx.id('hex'),
|
|
118
|
+
sourceOutputIndex: 0,
|
|
119
|
+
sourceSatoshis: fundingTx.outputs[0].satoshis,
|
|
120
|
+
lockingScript: fundingTx.outputs[0].lockingScript,
|
|
121
|
+
transactionVersion: tx.version,
|
|
122
|
+
otherInputs: [],
|
|
123
|
+
outputs: tx.outputs,
|
|
124
|
+
inputIndex: 0,
|
|
125
|
+
unlockingScript: input.unlockingScript,
|
|
126
|
+
inputSequence: input.sequence,
|
|
127
|
+
lockTime: tx.lockTime,
|
|
128
|
+
});
|
|
129
|
+
expect(spend.validate()).toBe(true);
|
|
130
|
+
// (c) broadcast through services.postBeef
|
|
131
|
+
expect(posted).toHaveLength(1);
|
|
132
|
+
expect(posted[0].txids).toEqual([txid]);
|
|
133
|
+
expect(posted[0].beef.findTxid(txid)).toBeDefined();
|
|
134
|
+
});
|
|
135
|
+
test('throws when the broadcast is not accepted', async () => {
|
|
136
|
+
const { ctx } = fakeContext({ broadcast: 'error' });
|
|
137
|
+
const provider = createWalletFundingProvider(ctx, { feeModel });
|
|
138
|
+
await expect(provider.fund(targetArgs())).rejects.toThrow('funding-broadcast-failed: REJECTED');
|
|
139
|
+
});
|
|
140
|
+
test('includes signed caller inputs first, verbatim, funding input last', async () => {
|
|
141
|
+
const { ctx } = fakeContext();
|
|
142
|
+
const provider = createWalletFundingProvider(ctx, { feeModel });
|
|
143
|
+
const callerKey = PrivateKey.fromHex('04'.repeat(32));
|
|
144
|
+
const callerSource = minedParent(new P2PKH().lock(callerKey.toPublicKey().toAddress()));
|
|
145
|
+
const args = targetArgs();
|
|
146
|
+
// The caller signs ALL|ANYONECANPAY over its own input and the outputs.
|
|
147
|
+
const signed = new Transaction();
|
|
148
|
+
signed.addInput({
|
|
149
|
+
sourceTransaction: callerSource,
|
|
150
|
+
sourceOutputIndex: 0,
|
|
151
|
+
unlockingScriptTemplate: new P2PKH().unlock(callerKey, 'all', true),
|
|
152
|
+
sequence: 0xffffffff,
|
|
153
|
+
});
|
|
154
|
+
for (const o of args.outputs ?? []) {
|
|
155
|
+
signed.addOutput({
|
|
156
|
+
lockingScript: LockingScript.fromHex(o.lockingScript),
|
|
157
|
+
satoshis: o.satoshis,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
await signed.sign();
|
|
161
|
+
const callerScript = signed.inputs[0].unlockingScript?.toHex();
|
|
162
|
+
const { tx: beef } = await provider.fund({
|
|
163
|
+
...args,
|
|
164
|
+
inputBEEF: callerSource.toBEEF(),
|
|
165
|
+
inputs: [
|
|
166
|
+
{
|
|
167
|
+
outpoint: `${callerSource.id('hex')}.0`,
|
|
168
|
+
unlockingScript: callerScript,
|
|
169
|
+
inputDescription: 'caller',
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
const tx = Transaction.fromAtomicBEEF(beef);
|
|
174
|
+
expect(tx.inputs).toHaveLength(2);
|
|
175
|
+
expect(tx.inputs[0].sourceTXID ?? tx.inputs[0].sourceTransaction?.id('hex')).toBe(callerSource.id('hex'));
|
|
176
|
+
expect(tx.inputs[0].unlockingScript?.toHex()).toBe(callerScript);
|
|
177
|
+
const fundingTx = tx.inputs[1].sourceTransaction;
|
|
178
|
+
expect(fundingTx.outputs[0].lockingScript.toHex()).toStartWith('76a914');
|
|
179
|
+
// both inputs still validate in the final transaction
|
|
180
|
+
for (const [i, src] of [callerSource, fundingTx].entries()) {
|
|
181
|
+
const input = tx.inputs[i];
|
|
182
|
+
const spend = new Spend({
|
|
183
|
+
sourceTXID: src.id('hex'),
|
|
184
|
+
sourceOutputIndex: 0,
|
|
185
|
+
sourceSatoshis: src.outputs[0].satoshis,
|
|
186
|
+
lockingScript: src.outputs[0].lockingScript,
|
|
187
|
+
transactionVersion: tx.version,
|
|
188
|
+
otherInputs: tx.inputs
|
|
189
|
+
.filter((_, j) => j !== i)
|
|
190
|
+
.map((inp) => ({
|
|
191
|
+
sourceTXID: inp.sourceTXID ?? inp.sourceTransaction?.id('hex'),
|
|
192
|
+
sourceOutputIndex: inp.sourceOutputIndex,
|
|
193
|
+
sequence: inp.sequence,
|
|
194
|
+
})),
|
|
195
|
+
outputs: tx.outputs,
|
|
196
|
+
inputIndex: i,
|
|
197
|
+
unlockingScript: input.unlockingScript,
|
|
198
|
+
inputSequence: input.sequence,
|
|
199
|
+
lockTime: tx.lockTime,
|
|
200
|
+
});
|
|
201
|
+
expect(spend.validate()).toBe(true);
|
|
202
|
+
}
|
|
203
|
+
// fee covers both inputs: input value - outputs >= the signed tx's fee
|
|
204
|
+
const inSats = callerSource.outputs[0].satoshis +
|
|
205
|
+
fundingTx.outputs[0].satoshis;
|
|
206
|
+
const outSats = tx.outputs.reduce((n, o) => n + o.satoshis, 0);
|
|
207
|
+
expect(inSats - outSats).toBeGreaterThanOrEqual(await feeModel.computeFee(tx));
|
|
208
|
+
});
|
|
209
|
+
test('rejects a caller input with no unlocking script', async () => {
|
|
210
|
+
const { ctx, created } = fakeContext();
|
|
211
|
+
const provider = createWalletFundingProvider(ctx, { feeModel });
|
|
212
|
+
await expect(provider.fund({
|
|
213
|
+
...targetArgs(),
|
|
214
|
+
inputs: [
|
|
215
|
+
{
|
|
216
|
+
outpoint: `${'ab'.repeat(32)}.0`,
|
|
217
|
+
unlockingScriptLength: 108,
|
|
218
|
+
inputDescription: 'x',
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
})).rejects.toThrow('wallet-funding-input-unsigned');
|
|
222
|
+
expect(created).toHaveLength(0);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
//# sourceMappingURL=walletFunding.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walletFunding.test.js","sourceRoot":"","sources":["../../src/funding/walletFunding.test.ts"],"names":[],"mappings":"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"}
|