Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 57x 57x 57x 8x 8x 8x 8x 12x 12x 6x 6x 8x 8x 6x 6x 6x 6x 6x 6x 6x 8x 8x 8x 8x 8x 8x 8x 8x | import { Beef, InternalizeActionArgs, InternalizeActionResult, InternalizeOutput, P2PKH, WalletProtocol } from '@bsv/sdk'
import { sdk } from "../../index.client";
import { WalletSigner } from "../WalletSigner";
/**
* Internalize Action allows a wallet to take ownership of outputs in a pre-existing transaction.
* The transaction may, or may not already be known to both the storage and user.
*
* Two types of outputs are handled: "wallet payments" and "basket insertions".
*
* A "basket insertion" output is considered a custom output and has no effect on the wallet's "balance".
*
* A "wallet payment" adds an outputs value to the wallet's change "balance". These outputs are assigned to the "default" basket.
*
* Processing starts with simple validation and then checks for a pre-existing transaction.
* If the transaction is already known to the user, then the outputs are reviewed against the existing outputs treatment,
* and merge rules are added to the arguments passed to the storage layer.
* The existing transaction must be in the 'unproven' or 'completed' status. Any other status is an error.
*
* When the transaction already exists, the description is updated. The isOutgoing sense is not changed.
*
* "basket insertion" Merge Rules:
* 1. The "default" basket may not be specified as the insertion basket.
* 2. A change output in the "default" basket may not be target of an insertion into a different basket.
* 3. These baskets do not affect the wallet's balance and are typed "custom".
*
* "wallet payment" Merge Rules:
* 1. Targetting an existing change "default" basket output results in a no-op. No error. No alterations made.
* 2. Targetting a previously "custom" non-change output converts it into a change output. This alters the transaction's `amount`, and the wallet balance.
*
*
* @param ninja
* @param vargs
* @param originator
* @returns
*/
export async function internalizeAction(
signer: WalletSigner,
auth: sdk.AuthId,
args: InternalizeActionArgs
)
: Promise<InternalizeActionResult> {
const vargs = sdk.validateInternalizeActionArgs(args)
const { ab, tx, txid } = await validateAtomicBeef();
const brc29ProtocolID: WalletProtocol = [2, '3241645161d8']
for (const o of vargs.outputs) {
Iif (o.outputIndex < 0 || o.outputIndex >= tx.outputs.length)
throw new sdk.WERR_INVALID_PARAMETER('outputIndex', `a valid output index in range 0 to ${tx.outputs.length - 1}`);
switch (o.protocol) {
case 'basket insertion': setupBasketInsertionForOutput(o, vargs); break;
case 'wallet payment': setupWalletPaymentForOutput(o, vargs); break;
default: throw new sdk.WERR_INTERNAL(`unexpected protocol ${o.protocol}`)
}
}
const r: InternalizeActionResult = await signer.storage.internalizeAction(args)
return r
function setupWalletPaymentForOutput(o: InternalizeOutput, dargs: sdk.ValidInternalizeActionArgs) {
const p = o.paymentRemittance
const output = tx.outputs[o.outputIndex]
Iif (!p) throw new sdk.WERR_INVALID_PARAMETER('paymentRemitance', `valid for protocol ${o.protocol}`);
const keyID = `${p.derivationPrefix} ${p.derivationSuffix}`
const privKey = signer.keyDeriver!.derivePrivateKey(brc29ProtocolID, keyID, p.senderIdentityKey)
const expectedLockScript = new P2PKH().lock(privKey.toAddress())
Iif (output.lockingScript.toHex() !== expectedLockScript.toHex())
throw new sdk.WERR_INVALID_PARAMETER('paymentRemitance', `locked by script conforming to BRC-29`);
}
function setupBasketInsertionForOutput(o: InternalizeOutput, dargs: sdk.ValidInternalizeActionArgs) {
/*
No additional validations...
*/
}
async function validateAtomicBeef() {
const ab = Beef.fromBinary(vargs.tx);
const txValid = await ab.verify(await signer.getServices().getChainTracker(), false);
Iif (!txValid || !ab.atomicTxid)
throw new sdk.WERR_INVALID_PARAMETER('tx', 'valid AtomicBEEF');
const txid = ab.atomicTxid;
const btx = ab.findTxid(txid);
Iif (!btx)
throw new sdk.WERR_INVALID_PARAMETER('tx', `valid AtomicBEEF with newest txid of ${txid}`);
const tx = btx.tx;
/*
for (const i of tx.inputs) {
if (!i.sourceTXID)
throw new sdk.WERR_INTERNAL('beef Transactions must have sourceTXIDs')
if (!i.sourceTransaction) {
const btx = ab.findTxid(i.sourceTXID)
if (!btx)
throw new sdk.WERR_INVALID_PARAMETER('tx', `valid AtomicBEEF and contain input transaction with txid ${i.sourceTXID}`);
i.sourceTransaction = btx.tx
}
}
*/
return { ab, tx, txid }
}
}
|