Skip to content

Commit 516fa2d

Browse files
authored
Implement strkey functions for liquidity pools and claimable balance ids (#5640)
1 parent 5ccaef0 commit 516fa2d

File tree

7 files changed

+187
-5
lines changed

7 files changed

+187
-5
lines changed

ingest/processors/token_transfer/helpers.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package token_transfer
33
import (
44
"crypto/sha256"
55
"fmt"
6+
67
"github.com/stellar/go/ingest"
8+
"github.com/stellar/go/strkey"
79
"github.com/stellar/go/xdr"
810
)
911

@@ -59,14 +61,12 @@ func protoAddressFromAccount(account xdr.MuxedAccount) string {
5961
return account.ToAccountId().Address()
6062
}
6163

62-
// TODO convert to strkey for LpId
6364
func lpIdToStrkey(lpId xdr.PoolId) string {
64-
return xdr.Hash(lpId).HexString()
65+
return strkey.MustEncode(strkey.VersionByteLiquidityPool, lpId[:])
6566
}
6667

67-
// TODO convert to strkey for CbId
6868
func cbIdToStrkey(cbId xdr.ClaimableBalanceId) string {
69-
return cbId.MustV0().HexString()
69+
return cbId.MustEncodeToStrkey()
7070
}
7171

7272
// This operation is used to only find CB entries that are either created or deleted, not updated

strkey/decode_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,31 @@ func TestDecode(t *testing.T) {
9999
},
100100
Address: "CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA",
101101
},
102+
{
103+
Name: "Liquidity Pool",
104+
ExpectedVersionByte: VersionByteLiquidityPool,
105+
ExpectedPayload: []byte{
106+
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
107+
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
108+
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
109+
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
110+
},
111+
Address: "LA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUPJN",
112+
},
113+
{
114+
Name: "Claimable Balance",
115+
ExpectedVersionByte: VersionByteClaimableBalance,
116+
ExpectedPayload: []byte{
117+
// first byte represents ClaimableBalanceIDType (in this case it's V0)
118+
0x00,
119+
// the remaining 32 bytes are the contents of the claimable balance hash
120+
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
121+
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
122+
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
123+
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
124+
},
125+
Address: "BAAD6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGR4TU",
126+
},
102127
}
103128

104129
for _, kase := range cases {

strkey/encode_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,31 @@ func TestEncode(t *testing.T) {
100100
},
101101
Expected: "CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA",
102102
},
103+
{
104+
Name: "Liquidity Pool",
105+
VersionByte: VersionByteLiquidityPool,
106+
Payload: []byte{
107+
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
108+
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
109+
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
110+
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
111+
},
112+
Expected: "LA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUPJN",
113+
},
114+
{
115+
Name: "Claimable Balance",
116+
VersionByte: VersionByteClaimableBalance,
117+
Payload: []byte{
118+
// first byte represents ClaimableBalanceIDType (in this case it's V0)
119+
0x00,
120+
// the remaining 32 bytes are the contents of the claimable balance hash
121+
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
122+
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
123+
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
124+
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
125+
},
126+
Expected: "BAAD6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGR4TU",
127+
},
103128
}
104129

105130
for _, kase := range cases {

strkey/main.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ const (
4141

4242
//VersionByteContract is the version byte used for encoded stellar contracts
4343
VersionByteContract = 2 << 3 // Base-32 encodes to 'C'
44+
45+
//VersionByteLiquidityPool is the version byte used for encoded stellar liquidity pools
46+
VersionByteLiquidityPool = 11 << 3
47+
48+
//VersionByteClaimableBalance is the version byte used for encoded stellar claimable balances
49+
VersionByteClaimableBalance = 1 << 3
4450
)
4551

4652
// maxPayloadSize is the maximum length of the payload for all versions. The
@@ -191,7 +197,9 @@ func Version(src string) (VersionByte, error) {
191197
// is not one of the defined valid version byte constants.
192198
func checkValidVersionByte(version VersionByte) error {
193199
switch version {
194-
case VersionByteAccountID, VersionByteMuxedAccount, VersionByteSeed, VersionByteHashTx, VersionByteHashX, VersionByteSignedPayload, VersionByteContract:
200+
case VersionByteAccountID, VersionByteMuxedAccount, VersionByteSeed,
201+
VersionByteHashTx, VersionByteHashX, VersionByteSignedPayload,
202+
VersionByteContract, VersionByteLiquidityPool, VersionByteClaimableBalance:
195203
return nil
196204
default:
197205
return ErrInvalidVersionByte

strkey/main_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ func TestVersion(t *testing.T) {
5151
Address: "CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA",
5252
ExpectedVersionByte: VersionByteContract,
5353
},
54+
{
55+
Name: "Liquidity Pool",
56+
Address: "LA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUPJN",
57+
ExpectedVersionByte: VersionByteLiquidityPool,
58+
},
59+
{
60+
Name: "Claimable Balance",
61+
Address: "BAAD6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGR4TU",
62+
ExpectedVersionByte: VersionByteClaimableBalance,
63+
},
5464
}
5565

5666
for _, kase := range cases {

xdr/claimable_balance_id.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package xdr
22

3+
import (
4+
"fmt"
5+
6+
"github.com/stellar/go/strkey"
7+
)
8+
39
func (e *EncodingBuffer) claimableBalanceCompressEncodeTo(cb ClaimableBalanceId) error {
410
if err := e.xdrEncoderBuf.WriteByte(byte(cb.Type)); err != nil {
511
return err
@@ -12,3 +18,49 @@ func (e *EncodingBuffer) claimableBalanceCompressEncodeTo(cb ClaimableBalanceId)
1218
panic("Unknown type")
1319
}
1420
}
21+
22+
// EncodeToStrkey returns the strkey encoding of the given claimable balance id
23+
// See SEP-23: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
24+
func (c ClaimableBalanceId) EncodeToStrkey() (string, error) {
25+
26+
switch c.Type {
27+
case ClaimableBalanceIdTypeClaimableBalanceIdTypeV0:
28+
hash := c.MustV0()
29+
payload := make([]byte, 0, len(hash)+1)
30+
payload = append(payload, byte(c.Type))
31+
payload = append(payload, hash[:]...)
32+
return strkey.Encode(strkey.VersionByteClaimableBalance, payload)
33+
default:
34+
return "", fmt.Errorf("unknown claimable balance id type: %v", c.Type)
35+
}
36+
}
37+
38+
// MustEncodeToStrkey returns the strkey encoding of the given claimable balance id
39+
// See SEP-23: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
40+
func (c ClaimableBalanceId) MustEncodeToStrkey() string {
41+
address, err := c.EncodeToStrkey()
42+
if err != nil {
43+
panic(err)
44+
}
45+
return address
46+
}
47+
48+
// DecodeFromStrkey parses a strkey encoded address into the given claimable balance id
49+
// See SEP-23: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
50+
func (c *ClaimableBalanceId) DecodeFromStrkey(address string) error {
51+
payload, err := strkey.Decode(strkey.VersionByteClaimableBalance, address)
52+
if err != nil {
53+
return err
54+
}
55+
expectedLen := len(Hash{}) + 1
56+
if len(payload) != expectedLen {
57+
return fmt.Errorf("invalid payload length, expected %v but got %v", expectedLen, len(payload))
58+
}
59+
if ClaimableBalanceIdType(payload[0]) != ClaimableBalanceIdTypeClaimableBalanceIdTypeV0 {
60+
return fmt.Errorf("invalid claimable balance id type: %v", payload[0])
61+
}
62+
c.Type = ClaimableBalanceIdTypeClaimableBalanceIdTypeV0
63+
c.V0 = &Hash{}
64+
copy(c.V0[:], payload[1:])
65+
return nil
66+
}

xdr/claimable_balance_id_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package xdr
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
8+
"github.com/stellar/go/gxdr"
9+
"github.com/stellar/go/randxdr"
10+
"github.com/stellar/go/strkey"
11+
)
12+
13+
func TestClaimableBalanceIdStrKey(t *testing.T) {
14+
gen := randxdr.NewGenerator()
15+
// generate 10,000 random claimable balance ids and ensure that the strkey
16+
// encoding / decoding round trips successfully
17+
for i := 0; i < 10000; i++ {
18+
id := &ClaimableBalanceId{}
19+
shape := &gxdr.ClaimableBalanceID{}
20+
gen.Next(
21+
shape,
22+
[]randxdr.Preset{},
23+
)
24+
assert.NoError(t, gxdr.Convert(shape, id))
25+
26+
encoded, err := id.EncodeToStrkey()
27+
assert.NoError(t, err)
28+
29+
var decoded ClaimableBalanceId
30+
assert.NoError(t, decoded.DecodeFromStrkey(encoded))
31+
32+
serializedBytes, err := id.MarshalBinary()
33+
assert.NoError(t, err)
34+
serializedDecoded, err := decoded.MarshalBinary()
35+
assert.NoError(t, err)
36+
assert.Equal(t, serializedBytes, serializedDecoded)
37+
}
38+
}
39+
40+
func TestClaimableBalanceIdDecodeErrors(t *testing.T) {
41+
var decoded ClaimableBalanceId
42+
payload := []byte{
43+
// first byte represents ClaimableBalanceIDType (in this case it's V0)
44+
0x00,
45+
// the remaining 32 bytes are the contents of the claimable balance hash
46+
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
47+
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
48+
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
49+
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
50+
}
51+
address := "BAAD6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGR4TU"
52+
assert.Equal(t, address, strkey.MustEncode(strkey.VersionByteClaimableBalance, payload))
53+
54+
payload[0] = 1
55+
invalidIdTypeAddress := strkey.MustEncode(strkey.VersionByteClaimableBalance, payload)
56+
assert.EqualError(t, decoded.DecodeFromStrkey(invalidIdTypeAddress), "invalid claimable balance id type: 1")
57+
58+
payload[0] = 0
59+
payload = append(payload, 0)
60+
invalidLengthAddress := strkey.MustEncode(strkey.VersionByteClaimableBalance, payload)
61+
assert.EqualError(t, decoded.DecodeFromStrkey(invalidLengthAddress), "invalid payload length, expected 33 but got 34")
62+
}

0 commit comments

Comments
 (0)