Skip to content

Commit 877f381

Browse files
author
Hack.bg R&D
committed
fix(wasm): accept rpc-shaped utxo
1 parent dd530e6 commit 877f381

7 files changed

Lines changed: 201 additions & 150 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ RUN apt update && apt install -yy curl just git
1515
ARG ELEMENTS="https://github.com/ElementsProject/elements/releases/download/elements-23.3.1/elements-23.3.1-x86_64-linux-gnu.tar.gz"
1616
RUN cd /usr/local && curl -Lf "${ELEMENTS}" | tar --strip-components=1 -xz
1717
# This draws the rest of the owl.
18-
ARG FADROMA_REF="fdd247c"
18+
ARG FADROMA_REF="b64fd93"
1919
ARG FADROMA_URL="https://github.com/hackbg/fadroma"
2020
RUN git clone --progress -b v3-alpha "${FADROMA_URL}" /fadroma && cd /fadroma && git checkout "${FADROMA_REF}"
2121
WORKDIR /fadroma

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,14 @@ The tests run on an automatically managed ephemeral Elements localnet in `elemen
253253
>The image clones a pinned commit of Fadroma when built;
254254
>this repo's tests then run in a subdirectory of that.
255255
256+
### Troubleshooting
257+
258+
* `Jet failed` from sanity check (PR#...)
259+
* `bad-txns-in-ne-out` when inputs/outputs do seem to add up
260+
* -> `VerifyAmounts` in Elements `confidential_validation.cpp` -> oh my...
261+
* Use `rpc.listunspent(0, 9999999, [sender])` to get a valid UTXO
262+
* `min-relay-fee` -> ?
263+
256264
## Acknowledgments, References, Attribution
257265

258266
This project applies techniques pioneered, described, or otherwise demonstrated

pkg/fadroma_simf.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export class Program {
5353
* Partially-signed redeem transaction without witnesses.
5454
* For manual signing.
5555
*/
56-
redeemPsbt(options: any): any;
56+
redeemPsbt(options: any): object;
5757
/**
5858
* Produce JSON dict of run-time parameter types.
5959
*/
@@ -85,11 +85,11 @@ export class Pst {
8585
/**
8686
* Show [PartiallySignedTransaction]
8787
*/
88-
toPset(): any;
88+
toPset(): object;
8989
/**
9090
* Simplified sign procedure.
9191
*/
92-
toSigned(keypair: Keypair): any;
92+
toSigned(keypair: Keypair): object;
9393
}
9494

9595
/**
@@ -109,9 +109,9 @@ export function paramTypes(source: string): object;
109109

110110
export function pst(arg: object): Pst;
111111

112-
export function sendSigned(signer: Keypair, options: any): any;
112+
export function sendSigned(signer: Keypair, options: any): object;
113113

114-
export function sendUnsigned(options: any): any;
114+
export function sendUnsigned(options: any): object;
115115

116116
export function sendUnsignedTx(options: any): object;
117117

pkg/fadroma_simf.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ export class Program {
394394
* Partially-signed redeem transaction without witnesses.
395395
* For manual signing.
396396
* @param {any} options
397-
* @returns {any}
397+
* @returns {object}
398398
*/
399399
redeemPsbt(options) {
400400
if (this.__wbg_ptr == 0) throw new Error('Attempt to use a moved value');
@@ -497,7 +497,7 @@ export class Pst {
497497
}
498498
/**
499499
* Show [PartiallySignedTransaction]
500-
* @returns {any}
500+
* @returns {object}
501501
*/
502502
toPset() {
503503
if (this.__wbg_ptr == 0) throw new Error('Attempt to use a moved value');
@@ -511,7 +511,7 @@ export class Pst {
511511
/**
512512
* Simplified sign procedure.
513513
* @param {Keypair} keypair
514-
* @returns {any}
514+
* @returns {object}
515515
*/
516516
toSigned(keypair) {
517517
if (this.__wbg_ptr == 0) throw new Error('Attempt to use a moved value');
@@ -583,7 +583,7 @@ export function pst(arg) {
583583
/**
584584
* @param {Keypair} signer
585585
* @param {any} options
586-
* @returns {any}
586+
* @returns {object}
587587
*/
588588
export function sendSigned(signer, options) {
589589
_assertClass(signer, Keypair);
@@ -599,7 +599,7 @@ export function sendSigned(signer, options) {
599599

600600
/**
601601
* @param {any} options
602-
* @returns {any}
602+
* @returns {object}
603603
*/
604604
export function sendUnsigned(options) {
605605
const ret = wasm.sendUnsigned(options);

src/lib.rs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,13 @@ type Maybe<T> = Result<T, JsError>;
181181
}
182182

183183
#[wasm_bindgen(js_name = sendSigned)]
184-
pub fn send_signed (signer: &Keypair, options: &JsValue) -> Maybe<JsValue> {
184+
pub fn send_signed (signer: &Keypair, options: &JsValue) -> Maybe<Object> {
185185
let (mut psbt, _) = send_from_js(options, None, None)?;
186186
Pst(psbt).to_signed(signer)
187187
}
188188

189189
#[wasm_bindgen(js_name = sendUnsigned)]
190-
pub fn send_unsigned (options: &JsValue) -> Maybe<JsValue> {
190+
pub fn send_unsigned (options: &JsValue) -> Maybe<Object> {
191191
ret_pst(&send_from_js(options, None, None)?.0)
192192
}
193193

@@ -284,16 +284,13 @@ pub fn pst (arg: Object) -> Maybe<Pst> {
284284
}
285285
/// Show [PartiallySignedTransaction]
286286
#[wasm_bindgen(js_name = toPset)]
287-
pub fn to_pset (&self) -> Maybe<JsValue> {
287+
pub fn to_pset (&self) -> Maybe<Object> {
288288
ret_pst(&self.0)
289289
}
290290
/// Simplified sign procedure.
291291
#[wasm_bindgen(js_name = toSigned)]
292-
pub fn to_signed (&self, keypair: &Keypair) -> Maybe<JsValue> {
293-
let signed = sign(&self, keypair)?;
294-
let result = ret_pst(&signed.0)?;
295-
set!(result, "signedHex", JsValue::from(pset_to_hex(&signed.0)?));
296-
Ok(result)
292+
pub fn to_signed (&self, keypair: &Keypair) -> Maybe<Object> {
293+
ret_pst(&sign(&self, keypair)?.0)
297294
}
298295
}
299296

@@ -454,7 +451,7 @@ pub fn witness_types (source: JsString) -> Maybe<Object> {
454451
/// Partially-signed redeem transaction without witnesses.
455452
/// For manual signing.
456453
#[wasm_bindgen(js_name = redeemPsbt)]
457-
pub fn redeem_psbt (&self, options: &JsValue) -> Maybe<JsValue> {
454+
pub fn redeem_psbt (&self, options: &JsValue) -> Maybe<Object> {
458455
ret_pst(&self.redeem_psbt_utxo(options)?.0)
459456
}
460457

@@ -668,11 +665,11 @@ fn arg_utxos (options: JsValue) -> Maybe<Vec<(OutPoint, TxOut)>> {
668665
}
669666

670667
fn arg_utxo (options: JsValue) -> Maybe<(OutPoint, TxOut)> {
671-
let txid = get!(options, "txid", arg_txid)?;
672-
let vout = get!(options, "vout", arg_vout)?;
673-
let recip = get!(options, "recipient", arg_address)?;
674-
let asset = get!(options, "asset", arg_asset_id)?;
675-
let value = get!(options, "value", arg_sats)?;
668+
let txid = get!(options, "txid", arg_txid)?;
669+
let vout = get!(options, "vout", arg_vout)?;
670+
let recip = get!(options, "address", arg_address)?;
671+
let asset = get!(options, "asset", arg_asset_id)?;
672+
let value = get!(options, "amount", arg_sats)?;
676673
Ok((OutPoint { txid, vout }, TxOut {
677674
script_pubkey: recip.script_pubkey(),
678675
value: TxValue::Explicit(value),
@@ -700,7 +697,7 @@ fn arg_sats (input: JsValue) -> Maybe<u64> {
700697
warn!("Number -> sats (u64): * 10^8; use BigInt to avoid precision issues");
701698
try_!("Number -> sats (u64)": f64::try_from(input).map(|x|(x * 100000000.0) as u64))
702699
} else if JsString::is_type_of(&input) {
703-
warn!("String -> sats (u64): use BigInt to avoid typing issues");
700+
warn!("String -> sats (u64): use BigInt to avoid type issues");
704701
try_debug!("String -> sats (u64)": u64::from_str(&input.as_string().unwrap_or_default()))
705702
} else {
706703
return err!("sats: received {:?}: need integer", input.js_typeof())
@@ -755,9 +752,11 @@ fn ret_tx (tx: &Transaction) -> Maybe<Object> {
755752
})
756753
}
757754

758-
fn ret_pst (psbt: &PartiallySignedTransaction) -> Maybe<JsValue> {
759-
match JSON::parse(serde_json::to_string(&psbt)?.as_str()) {
760-
Ok(psbt) => Ok(psbt),
761-
Err(_) => err!("failed to deserialize interim psbt")
762-
}
755+
fn ret_pst (pst: &PartiallySignedTransaction) -> Maybe<Object> {
756+
Ok(obj! {
757+
"global" = try_!("pst: serialize global": JSON::parse(serde_json::to_string(&pst.global)?.as_str()))?,
758+
"inputs" = try_!("pst: serialize inputs": JSON::parse(serde_json::to_string(&pst.inputs())?.as_str()))?,
759+
"outputs" = try_!("pst: serialize outputs": JSON::parse(serde_json::to_string(&pst.outputs())?.as_str()))?,
760+
"hex" = JsValue::from(pset_to_hex(&pst)?),
761+
})
763762
}

src/sdk.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ export async function Keypair (secret: Uint8Array): Promise<Keypair> {
7070
return keypair(secret)
7171
}
7272

73+
/** Wrap a [Keypair] as a Signer. */
74+
export async function Signer (secret: Uint8Array) {
75+
const { pubECDSA } = await import('npm:@scure/btc-signer/utils.js');
76+
return {
77+
keypair: await Keypair(secret),
78+
pubEcdsa: pubECDSA(secret),
79+
}
80+
}
81+
7382
/** Load [Wasm] with default settings and create a [Compiler]. */
7483
export async function Compiler (...args: Parameters<Wasm['compiler']>) {
7584
const { compiler } = await Wasm();

0 commit comments

Comments
 (0)