Skip to content

Commit 8d99007

Browse files
committed
Merge branch 'next-version' into vtxo-commitment-txids
2 parents 135c1c0 + b2c4a6e commit 8d99007

File tree

12 files changed

+111
-77
lines changed

12 files changed

+111
-77
lines changed

common/encoding.go

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,25 @@ import (
88
"github.com/decred/dcrd/dcrec/secp256k1/v4"
99
)
1010

11-
// Address represents an Ark address with HRP, server public key, and VTXO Taproot public key
11+
// Address represents an Ark address with Vvrsion, prefix, server public key, and VTXO taproot key.
1212
type Address struct {
13+
Version uint8
1314
HRP string
1415
Server *secp256k1.PublicKey
1516
VtxoTapKey *secp256k1.PublicKey
1617
}
1718

18-
// Encode converts the address to its bech32m string representation
19-
func (a *Address) Encode() (string, error) {
19+
// EncodeV0 converts the address to its bech32m string representation.
20+
func (a *Address) EncodeV0() (string, error) {
2021
if a.Server == nil {
2122
return "", fmt.Errorf("missing server public key")
2223
}
2324
if a.VtxoTapKey == nil {
24-
return "", fmt.Errorf("missing vtxo tap public key")
25+
return "", fmt.Errorf("missing vtxo taproot key")
2526
}
2627

2728
combinedKey := append(
28-
schnorr.SerializePubKey(a.Server), schnorr.SerializePubKey(a.VtxoTapKey)...,
29+
[]byte{byte(a.Version)}, append(schnorr.SerializePubKey(a.Server), schnorr.SerializePubKey(a.VtxoTapKey)...)...,
2930
)
3031
grp, err := bech32.ConvertBits(combinedKey, 8, 5, true)
3132
if err != nil {
@@ -34,35 +35,46 @@ func (a *Address) Encode() (string, error) {
3435
return bech32.EncodeM(a.HRP, grp)
3536
}
3637

37-
// DecodeAddress parses a bech32m encoded address string and returns an Address object
38-
func DecodeAddress(addr string) (*Address, error) {
38+
// DecodeAddressV0 parses a bech32m encoded address string and returns an Address struct.
39+
func DecodeAddressV0(addr string) (*Address, error) {
3940
if len(addr) == 0 {
40-
return nil, fmt.Errorf("address is empty")
41+
return nil, fmt.Errorf("mssing address")
4142
}
4243

4344
prefix, buf, err := bech32.DecodeNoLimit(addr)
4445
if err != nil {
4546
return nil, err
4647
}
4748
if prefix != Bitcoin.Addr && prefix != BitcoinTestNet.Addr && prefix != BitcoinRegTest.Addr {
48-
return nil, fmt.Errorf("invalid prefix")
49+
return nil, fmt.Errorf("unknown prefix")
4950
}
5051
grp, err := bech32.ConvertBits(buf, 5, 8, false)
5152
if err != nil {
5253
return nil, err
5354
}
5455

55-
serverKey, err := schnorr.ParsePubKey(grp[:32])
56-
if err != nil {
57-
return nil, fmt.Errorf("failed to parse public key: %s", err)
56+
// [version, serverKey, vtxoKey]
57+
if len(grp) != 1+32+32 {
58+
return nil, fmt.Errorf("invalid address bytes length, expected 65 got %d", len(grp))
59+
}
60+
61+
version := uint8(grp[0])
62+
if version != 0 {
63+
return nil, fmt.Errorf("invalid address version, expected 0 got %d", version)
5864
}
5965

60-
vtxoKey, err := schnorr.ParsePubKey(grp[32:])
66+
serverKey, err := schnorr.ParsePubKey(grp[1:33])
6167
if err != nil {
6268
return nil, fmt.Errorf("failed to parse server public key: %s", err)
6369
}
6470

71+
vtxoKey, err := schnorr.ParsePubKey(grp[33:])
72+
if err != nil {
73+
return nil, fmt.Errorf("failed to parse vtxo taproot key: %s", err)
74+
}
75+
6576
return &Address{
77+
Version: version,
6678
HRP: prefix,
6779
Server: serverKey,
6880
VtxoTapKey: vtxoKey,

common/encoding_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ func TestAddressEncoding(t *testing.T) {
2626
Address struct {
2727
Valid []struct {
2828
Addr string `json:"addr"`
29+
ExpectedVersion uint8 `json:"expectedVersion"`
30+
ExpectedPrefix string `json:"expectedPrefix"`
2931
ExpectedUserKey string `json:"expectedUserKey"`
3032
ExpectedServerKey string `json:"expectedServerKey"`
3133
} `json:"valid"`
@@ -40,29 +42,27 @@ func TestAddressEncoding(t *testing.T) {
4042

4143
t.Run("valid", func(t *testing.T) {
4244
for _, f := range fixtures.Address.Valid {
43-
addr, err := common.DecodeAddress(f.Addr)
44-
require.NoError(t, err)
45-
require.NotEmpty(t, addr.HRP)
46-
require.NotNil(t, addr.Server)
47-
require.NotNil(t, addr.VtxoTapKey)
48-
45+
addr, err := common.DecodeAddressV0(f.Addr)
4946
require.NoError(t, err)
47+
require.NotNil(t, addr)
48+
require.Equal(t, f.ExpectedVersion, addr.Version)
49+
require.Equal(t, f.ExpectedPrefix, addr.HRP)
5050
require.Equal(t, f.ExpectedUserKey, hex.EncodeToString(addr.VtxoTapKey.SerializeCompressed()))
51-
52-
require.NoError(t, err)
5351
require.Equal(t, f.ExpectedServerKey, hex.EncodeToString(addr.Server.SerializeCompressed()))
5452

55-
encoded, err := addr.Encode()
53+
encoded, err := addr.EncodeV0()
5654
require.NoError(t, err)
5755
require.Equal(t, f.Addr, encoded)
5856
}
5957
})
6058

6159
t.Run("invalid", func(t *testing.T) {
6260
for _, f := range fixtures.Address.Invalid {
63-
addr, err := common.DecodeAddress(f.Addr)
64-
require.EqualError(t, err, f.ExpectedError)
65-
require.Nil(t, addr)
61+
t.Run(f.ExpectedError, func(t *testing.T) {
62+
addr, err := common.DecodeAddressV0(f.Addr)
63+
require.Contains(t, err.Error(), f.ExpectedError)
64+
require.Nil(t, addr)
65+
})
6666
}
6767
})
6868
}

common/fixtures/encoding.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,21 @@
22
"address": {
33
"valid": [
44
{
5-
"addr": "tark1x0lm8hhr2wc6n6lyemtyh9rz8rg2ftpkfun46aca56kjg3ws0tsztfpuanaquxc6faedvjk3tax0575y6perapg3e95654pk8r4fjecs5fyd2",
5+
"addr": "tark1qqellv77udfmr20tun8dvju5vgudpf9vxe8jwhthrkn26fz96pawqfdy8nk05rsmrf8h94j26905e7n6sng8y059z8ykn2j5xcuw4xt846qj6x",
6+
"expectedVersion": 0,
7+
"expectedPrefix": "tark",
68
"expectedUserKey": "0225a43cecfa0e1b1a4f72d64ad15f4cfa7a84d0723e8511c969aa543638ea9967",
79
"expectedServerKey": "0233ffb3dee353b1a9ebe4ced64b946238d0a4ac364f275d771da6ad2445d07ae0"
810
}
911
],
1012
"invalid": [
1113
{
1214
"addr": "wrongprefix1qt9tfh7c09hlsstzq5y9tzuwyaesrwr8gpy8cn29cxv0flp64958s0n0yd0",
13-
"expectedError": "invalid prefix"
15+
"expectedError": "unknown prefix"
16+
},
17+
{
18+
"addr": "tark1x0lm8hhr2wc6n6lyemtyh9rz8rg2ftpkfun46aca56kjg3ws0tsztfpuanaquxc6faedvjk3tax0575y6perapg3e95654pk8r4fjecs5fyd2",
19+
"expectedError": "invalid address bytes length"
1420
}
1521
]
1622
}

pkg/client-sdk/base_client.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
walletstore "github.com/ark-network/ark/pkg/client-sdk/wallet/singlekey/store"
1919
filestore "github.com/ark-network/ark/pkg/client-sdk/wallet/singlekey/store/file"
2020
inmemorystore "github.com/ark-network/ark/pkg/client-sdk/wallet/singlekey/store/inmemory"
21-
"github.com/btcsuite/btcd/btcec/v2/schnorr"
2221
"github.com/decred/dcrd/dcrec/secp256k1/v4"
2322
)
2423

@@ -199,14 +198,16 @@ func (a *arkClient) NotifyIncomingFunds(
199198
return nil, fmt.Errorf("wallet not initialized")
200199
}
201200

202-
decoded, err := common.DecodeAddress(addr)
201+
decoded, err := common.DecodeAddressV0(addr)
203202
if err != nil {
204203
return nil, err
205204
}
206-
207-
scripts := []string{
208-
hex.EncodeToString(schnorr.SerializePubKey(decoded.VtxoTapKey)),
205+
script, err := common.P2TRScript(decoded.VtxoTapKey)
206+
if err != nil {
207+
return nil, err
209208
}
209+
210+
scripts := []string{hex.EncodeToString(script)}
210211
subId, err := a.indexer.SubscribeForScripts(ctx, "", scripts)
211212
if err != nil {
212213
return nil, err

pkg/client-sdk/client.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ func (a *covenantlessArkClient) SendOffChain(
506506
return "", fmt.Errorf("all receiver addresses must be offchain addresses")
507507
}
508508

509-
addr, err := common.DecodeAddress(receiver.To)
509+
addr, err := common.DecodeAddressV0(receiver.To)
510510
if err != nil {
511511
return "", fmt.Errorf("invalid receiver address: %s", err)
512512
}
@@ -1070,23 +1070,24 @@ func (a *covenantlessArkClient) listenForArkTxs(ctx context.Context) {
10701070
continue
10711071
}
10721072

1073-
myPubkeys := make(map[string]struct{})
1073+
myScripts := make(map[string]struct{})
10741074
for _, addr := range offchainAddrs {
1075-
// nolint:all
1076-
decoded, _ := common.DecodeAddress(addr.Address)
1077-
pubkey := hex.EncodeToString(decoded.VtxoTapKey.SerializeCompressed()[1:])
1078-
myPubkeys[pubkey] = struct{}{}
1075+
// nolint
1076+
decoded, _ := common.DecodeAddressV0(addr.Address)
1077+
// nolint
1078+
script, _ := common.P2TRScript(decoded.VtxoTapKey)
1079+
myScripts[hex.EncodeToString(script)] = struct{}{}
10791080
}
10801081

10811082
if event.CommitmentTx != nil {
1082-
if err := a.handleCommitmentTx(ctxBg, myPubkeys, event.CommitmentTx); err != nil {
1083+
if err := a.handleCommitmentTx(ctxBg, myScripts, event.CommitmentTx); err != nil {
10831084
log.WithError(err).Error("failed to process commitment tx")
10841085
continue
10851086
}
10861087
}
10871088

10881089
if event.ArkTx != nil {
1089-
if err := a.handleArkTx(ctxBg, myPubkeys, event.ArkTx); err != nil {
1090+
if err := a.handleArkTx(ctxBg, myScripts, event.ArkTx); err != nil {
10901091
log.WithError(err).Error("failed to process ark tx")
10911092
continue
10921093
}
@@ -1626,7 +1627,7 @@ func (a *covenantlessArkClient) sendOffchain(
16261627

16271628
// validate receivers and create outputs
16281629
for _, receiver := range receivers {
1629-
rcvAddr, err := common.DecodeAddress(receiver.To)
1630+
rcvAddr, err := common.DecodeAddressV0(receiver.To)
16301631
if err != nil {
16311632
return "", fmt.Errorf("invalid receiver address: %s", err)
16321633
}
@@ -1980,7 +1981,7 @@ func (a *covenantlessArkClient) handleBatchEvents(
19801981
step := start
19811982
hasOffchainOutput := false
19821983
for _, receiver := range receivers {
1983-
if _, err := common.DecodeAddress(receiver.To); err == nil {
1984+
if _, err := common.DecodeAddressV0(receiver.To); err == nil {
19841985
hasOffchainOutput = true
19851986
break
19861987
}
@@ -2513,7 +2514,7 @@ func (a *covenantlessArkClient) validateOffchainReceiver(
25132514
) error {
25142515
found := false
25152516

2516-
rcvAddr, err := common.DecodeAddress(receiver.To)
2517+
rcvAddr, err := common.DecodeAddressV0(receiver.To)
25172518
if err != nil {
25182519
return err
25192520
}

pkg/client-sdk/types/types.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,11 @@ func (v Vtxo) IsRecoverable() bool {
7373
}
7474

7575
func (v Vtxo) Address(server *secp256k1.PublicKey, net common.Network) (string, error) {
76-
pubkeyBytes, err := hex.DecodeString(v.Script)
76+
buf, err := hex.DecodeString(v.Script)
7777
if err != nil {
7878
return "", err
7979
}
80+
pubkeyBytes := buf[2:]
8081

8182
pubkey, err := schnorr.ParsePubKey(pubkeyBytes)
8283
if err != nil {
@@ -89,7 +90,7 @@ func (v Vtxo) Address(server *secp256k1.PublicKey, net common.Network) (string,
8990
VtxoTapKey: pubkey,
9091
}
9192

92-
return a.Encode()
93+
return a.EncodeV0()
9394
}
9495

9596
type VtxoEventType int
@@ -198,7 +199,7 @@ func (o Receiver) ToTxOut() (*wire.TxOut, bool, error) {
198199
var pkScript []byte
199200
isOnchain := false
200201

201-
arkAddress, err := common.DecodeAddress(o.To)
202+
arkAddress, err := common.DecodeAddressV0(o.To)
202203
if err != nil {
203204
// decode onchain address
204205
btcAddress, err := btcutil.DecodeAddress(o.To, nil)

pkg/client-sdk/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func buildOffchainTx(
9696
return "", nil, fmt.Errorf("receiver %d is onchain", i)
9797
}
9898

99-
addr, err := common.DecodeAddress(receiver.To)
99+
addr, err := common.DecodeAddressV0(receiver.To)
100100
if err != nil {
101101
return "", nil, err
102102
}

pkg/client-sdk/wallet/singlekey/bitcoin_wallet.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (w *bitcoinWallet) GetAddresses(
5151
return nil, nil, nil, nil, err
5252
}
5353

54-
encodedOffchainAddr, err := offchainAddr.Address.Encode()
54+
encodedOffchainAddr, err := offchainAddr.Address.EncodeV0()
5555
if err != nil {
5656
return nil, nil, nil, nil, err
5757
}
@@ -106,7 +106,7 @@ func (w *bitcoinWallet) NewAddress(
106106
return "", nil, nil, err
107107
}
108108

109-
encodedOffchainAddr, err := offchainAddr.Address.Encode()
109+
encodedOffchainAddr, err := offchainAddr.Address.EncodeV0()
110110
if err != nil {
111111
return "", nil, nil, err
112112
}
@@ -133,7 +133,7 @@ func (w *bitcoinWallet) NewAddresses(
133133
offchainAddrs := make([]wallet.TapscriptsAddress, 0, num)
134134
boardingAddrs := make([]wallet.TapscriptsAddress, 0, num)
135135
for i := 0; i < num; i++ {
136-
encodedOffchainAddr, err := offchainAddr.Address.Encode()
136+
encodedOffchainAddr, err := offchainAddr.Address.EncodeV0()
137137
if err != nil {
138138
return nil, nil, nil, err
139139
}

server/internal/core/application/service.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ func (s *covenantlessService) SignRoundTx(ctx context.Context, signedRoundTx str
12341234
}
12351235

12361236
func (s *covenantlessService) ListVtxos(ctx context.Context, address string) ([]domain.Vtxo, []domain.Vtxo, error) {
1237-
decodedAddress, err := common.DecodeAddress(address)
1237+
decodedAddress, err := common.DecodeAddressV0(address)
12381238
if err != nil {
12391239
return nil, nil, fmt.Errorf("failed to decode address: %s", err)
12401240
}
@@ -1366,7 +1366,7 @@ func (s *covenantlessService) GetTxRequestQueue(
13661366
VtxoTapKey: vtxoTapKey,
13671367
}
13681368

1369-
addressStr, err := address.Encode()
1369+
addressStr, err := address.EncodeV0()
13701370
if err != nil {
13711371
return nil, fmt.Errorf("failed to encode address: %s", err)
13721372
}

0 commit comments

Comments
 (0)