Skip to content

Commit cbec16e

Browse files
committed
Add coin purchase memo support
1 parent c1e6c27 commit cbec16e

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

api/firmware/paymentrequests.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ func ComputePaymentRequestSighash(
4444
case *messages.BTCPaymentRequestRequest_Memo_TextMemo_:
4545
_ = binary.Write(sighash, binary.LittleEndian, uint32(1))
4646
hashDataLenPrefixed(sighash, []byte(m.TextMemo.Note))
47+
case *messages.BTCPaymentRequestRequest_Memo_CoinPurchaseMemo_:
48+
// CoinPurchaseMemo type = 3 in SLIP-24 (not the protobuf field number!)
49+
_ = binary.Write(sighash, binary.LittleEndian, uint32(3))
50+
// Hash the SLIP-24 fields: coin_type, amount, address
51+
_ = binary.Write(sighash, binary.LittleEndian, m.CoinPurchaseMemo.CoinType)
52+
hashDataLenPrefixed(sighash, []byte(m.CoinPurchaseMemo.Amount))
53+
hashDataLenPrefixed(sighash, []byte(m.CoinPurchaseMemo.Address))
54+
// Note: address_derivation field is NOT hashed.
4755
default:
4856
return nil, errors.New("unsupported memo type")
4957
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package firmware
2+
3+
import (
4+
"encoding/hex"
5+
"testing"
6+
7+
"github.com/BitBoxSwiss/bitbox02-api-go/api/firmware/messages"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
// TODO: Add integration test for CoinPurchaseMemo once the firmware UI is implemented.
12+
// potentially in psbt_test.go
13+
14+
func TestComputePaymentRequestSighash_CoinPurchaseMemo(t *testing.T) {
15+
// This test verifies that our Go sighash computation matches the firmware's Rust implementation.
16+
// The expected hash comes from the firmware test at:
17+
// bitbox02-firmware/src/rust/bitbox02-rust/src/hww/api/bitcoin/payment_request.rs:366-369
18+
19+
paymentRequest := &messages.BTCPaymentRequestRequest{
20+
RecipientName: "Merchant",
21+
Memos: []*messages.BTCPaymentRequestRequest_Memo{
22+
{
23+
Memo: &messages.BTCPaymentRequestRequest_Memo_CoinPurchaseMemo_{
24+
CoinPurchaseMemo: &messages.BTCPaymentRequestRequest_Memo_CoinPurchaseMemo{
25+
CoinType: 60, // Ethereum
26+
Amount: "0.25 ETH",
27+
Address: "0xabc1234567890",
28+
// address_derivation is intentionally nil, since it's not part of the sighash
29+
},
30+
},
31+
},
32+
},
33+
Nonce: []byte{},
34+
TotalAmount: 123456,
35+
Signature: []byte{},
36+
}
37+
38+
sighash, err := ComputePaymentRequestSighash(
39+
paymentRequest,
40+
1, // SLIP-44 coin type for Bitcoin Testnet
41+
123456,
42+
"tb1q2q0j6gmfxynj40p0kxsr9jkagcvgpuqvqynnup",
43+
)
44+
require.NoError(t, err)
45+
46+
expectedHash := "1806caf7c518aad69eb38f25fd418d507c6a3e01719a7d77be94cd50a2790872"
47+
actualHash := hex.EncodeToString(sighash)
48+
49+
require.Equal(t, expectedHash, actualHash, "Sighash mismatch: Go implementation doesn't match firmware")
50+
}

0 commit comments

Comments
 (0)