diff --git a/address.go b/address.go index 5f7fba8..4aac6b6 100644 --- a/address.go +++ b/address.go @@ -11,10 +11,12 @@ import ( type AddressType byte +// refer to pg.120 in https://hydra.iohk.io/build/7918420/download/1/ledger-spec.pdf const ( Base AddressType = 0x00 Ptr AddressType = 0x04 Enterprise AddressType = 0x06 + Stake AddressType = 0x0E ) // Address represents a Cardano address. @@ -94,7 +96,7 @@ func NewAddressFromBytes(bytes []byte) (Address, error) { } case Ptr: if len(bytes) <= 29 { - return addr, errors.New("enterprise address length should be greater than 29") + return addr, errors.New("pointer address length should be greater than 29") } index := uint(29) @@ -120,7 +122,7 @@ func NewAddressFromBytes(bytes []byte) (Address, error) { addr.Pointer = Pointer{Slot: slot, TxIndex: txIndex, CertIndex: certIndex} case Ptr + 1: if len(bytes) <= 29 { - return addr, errors.New("enterprise address length should be greater than 29") + return addr, errors.New("pointer address length should be greater than 29") } index := uint(29) @@ -160,6 +162,22 @@ func NewAddressFromBytes(bytes []byte) (Address, error) { Type: ScriptCredential, ScriptHash: bytes[1:29], } + case Stake: + if len(bytes) != 29 { + return addr, errors.New("stake address length should be 29") + } + addr.Stake = StakeCredential{ + Type: KeyCredential, + KeyHash: bytes[1:29], + } + case Stake + 1: + if len(bytes) != 29 { + return addr, errors.New("stake address length should be 29") + } + addr.Stake = StakeCredential{ + Type: ScriptCredential, + ScriptHash: bytes[1:29], + } } return addr, nil @@ -206,13 +224,15 @@ func (addr *Address) Bytes() []byte { case Base, Base + 1, Base + 2, Base + 3: addrBytes = append(addrBytes, addr.Payment.Hash()...) addrBytes = append(addrBytes, addr.Stake.Hash()...) - case Enterprise, Enterprise + 1: - addrBytes = append(addrBytes, addr.Payment.Hash()...) case Ptr, Ptr + 1: addrBytes = append(addrBytes, addr.Payment.Hash()...) addrBytes = append(addrBytes, encodeToNat(addr.Pointer.Slot)...) addrBytes = append(addrBytes, encodeToNat(addr.Pointer.TxIndex)...) addrBytes = append(addrBytes, encodeToNat(addr.Pointer.CertIndex)...) + case Enterprise, Enterprise + 1: + addrBytes = append(addrBytes, addr.Payment.Hash()...) + case Stake, Stake + 1: + addrBytes = append(addrBytes, addr.Stake.Hash()...) } return addrBytes @@ -220,7 +240,7 @@ func (addr *Address) Bytes() []byte { // Bech32 returns the Address encoded as bech32. func (addr *Address) Bech32() string { - addrStr, err := bech32.EncodeFromBase256(getHrp(addr.Network), addr.Bytes()) + addrStr, err := bech32.EncodeFromBase256(getHrp(addr.Network, addr.Type), addr.Bytes()) if err != nil { panic(err) } @@ -245,15 +265,6 @@ func NewBaseAddress(network Network, payment StakeCredential, stake StakeCredent return Address{Type: addrType, Network: network, Payment: payment, Stake: stake}, nil } -// NewEnterpriseAddress returns a new Enterprise Address. -func NewEnterpriseAddress(network Network, payment StakeCredential) (Address, error) { - addrType := Enterprise - if payment.Type == ScriptCredential { - addrType = Enterprise + 1 - } - return Address{Type: addrType, Network: network, Payment: payment}, nil -} - // Pointer is the location of the Stake Registration Certificate in the blockchain. type Pointer struct { Slot uint64 @@ -270,6 +281,24 @@ func NewPointerAddress(network Network, payment StakeCredential, ptr Pointer) (A return Address{Type: addrType, Network: network, Payment: payment, Pointer: ptr}, nil } +// NewEnterpriseAddress returns a new Enterprise Address. +func NewEnterpriseAddress(network Network, payment StakeCredential) (Address, error) { + addrType := Enterprise + if payment.Type == ScriptCredential { + addrType = Enterprise + 1 + } + return Address{Type: addrType, Network: network, Payment: payment}, nil +} + +// NewStakeAddress returns a new Stake Address. +func NewStakeAddress(network Network, stake StakeCredential) (Address, error) { + addrType := Stake + if stake.Type == ScriptCredential { + addrType = Stake + 1 + } + return Address{Type: addrType, Network: network, Stake: stake}, nil +} + func decodeFromNat(data []byte) (uint64, uint, error) { out := big.NewInt(0) n := uint(0) @@ -316,11 +345,16 @@ func Blake224Hash(b []byte) ([]byte, error) { return hash.Sum(nil), err } -func getHrp(network Network) string { +func getHrp(network Network, addrType AddressType) string { + hrp := "addr" + if addrType == Stake || addrType == Stake+1 { + hrp = "stake" + } + switch network { case Testnet, Preprod: - return "addr_test" + return hrp + "_test" default: - return "addr" + return hrp } } diff --git a/address_test.go b/address_test.go index 65d5d07..fd4cbd0 100644 --- a/address_test.go +++ b/address_test.go @@ -8,17 +8,19 @@ import ( ) const ( - paymentKey = "addr_vk1w0l2sr2zgfm26ztc6nl9xy8ghsk5sh6ldwemlpmp9xylzy4dtf7st80zhd" - stakeKey = "stake_vk1px4j0r2fk7ux5p23shz8f3y5y2qam7s954rgf3lg5merqcj6aetsft99wu" - scriptHash = "script1cda3khwqv60360rp5m7akt50m6ttapacs8rqhn5w342z7r35m37" - addrType0 = "addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x" - addrType1 = "addr1z8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gten0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgs9yc0hh" - addrType2 = "addr1yx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzerkr0vd4msrxnuwnccdxlhdjar77j6lg0wypcc9uar5d2shs2z78ve" - addrType3 = "addr1x8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gt7r0vd4msrxnuwnccdxlhdjar77j6lg0wypcc9uar5d2shskhj42g" - addrType4 = "addr1gx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer5pnz75xxcrzqf96k" - addrType5 = "addr128phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtupnz75xxcrtw79hu" - addrType6 = "addr1vx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzers66hrl8" - addrType7 = "addr1w8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcyjy7wx" + paymentKey = "addr_vk1w0l2sr2zgfm26ztc6nl9xy8ghsk5sh6ldwemlpmp9xylzy4dtf7st80zhd" + stakeKey = "stake_vk1px4j0r2fk7ux5p23shz8f3y5y2qam7s954rgf3lg5merqcj6aetsft99wu" + scriptHash = "script1cda3khwqv60360rp5m7akt50m6ttapacs8rqhn5w342z7r35m37" + addrType0 = "addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x" + addrType1 = "addr1z8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gten0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgs9yc0hh" + addrType2 = "addr1yx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzerkr0vd4msrxnuwnccdxlhdjar77j6lg0wypcc9uar5d2shs2z78ve" + addrType3 = "addr1x8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gt7r0vd4msrxnuwnccdxlhdjar77j6lg0wypcc9uar5d2shskhj42g" + addrType4 = "addr1gx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer5pnz75xxcrzqf96k" + addrType5 = "addr128phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtupnz75xxcrtw79hu" + addrType6 = "addr1vx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzers66hrl8" + addrType7 = "addr1w8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcyjy7wx" + stakeAddrType1 = "stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw" + stakeAddrType2 = "stake178phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcccycj5" ) var ( @@ -31,6 +33,8 @@ var ( "addr128phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtupnz75xxcrtw79hu", "addr1vx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzers66hrl8", "addr1w8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcyjy7wx", + "stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw", + "stake178phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcccycj5", } ) @@ -140,6 +144,22 @@ func TestNewAddress(t *testing.T) { if got, want := enterprise1.Bech32(), addrType7; got != want { t.Errorf("invalid enterprise address\ngot: %s\nwant: %s", got, want) } + + stake0, err := NewStakeAddress(Mainnet, stakeAddrCred) + if err != nil { + t.Fatal(err) + } + if got, want := stake0.Bech32(), stakeAddrType1; got != want { + t.Errorf("invalid stake address\ngot: %s\nwant: %s", got, want) + } + + stake1, err := NewStakeAddress(Mainnet, scriptCred) + if err != nil { + t.Fatal(err) + } + if got, want := stake1.Bech32(), stakeAddrType2; got != want { + t.Errorf("invalid stake address\ngot: %s\nwant: %s", got, want) + } } func TestNat(t *testing.T) { diff --git a/wallet/client_test.go b/wallet/client_test.go index 62122b8..3050003 100644 --- a/wallet/client_test.go +++ b/wallet/client_test.go @@ -7,49 +7,57 @@ import ( ) type TestVector struct { - mnemonic string - rootXsk string - addrXsk0 string - addrXvk0 string - addrXsk1 string - addrXvk1 string - paymentAddr0 string - paymentAddr1 string + mnemonic string + rootXsk string + addrXsk0 string + addrXvk0 string + addrXsk1 string + addrXvk1 string + paymentBaseAddr0 string + paymentEnterpriseAddr0 string + paymentEnterpriseAddr1 string + stakeAddr string } var testVectors = []TestVector{ // 15 words { - mnemonic: "art forum devote street sure rather head chuckle guard poverty release quote oak craft enemy", - rootXsk: "root_xsk1hretan5mml3tq2p0twkhq4tz4jvka7m2l94kfr6yghkyfar6m9wppc7h9unw6p65y23kakzct3695rs32z7vaw3r2lg9scmfj8ec5du3ufydu5yuquxcz24jlkjhsc9vsa4ufzge9s00fn398svhacse5sh85djs", - addrXsk0: "addr_xsk1fzgcl9km0mve2jwe8qxve364w6te9vpddhwpw5g8wnjlupmmm9wxpdda6jaglx7smwl6qd5xuzjcweeq8ykp0wg9hng4pg6eumwx2t90swaed7ehsa6j86qsw3fnl4thtemsng6vukmz6ddf3cnd4sfkzu74xjqg", - addrXvk0: "addr_xvk1fz009r4f0aceaemksezlca9cz8p8rewhaurvyvgg2ndnq9vwj3w6lqamjman0pm4y05pqazn8l2hwhnhpx35eedk9566nr3xmtqnv9ccm4zyu", - addrXsk1: "addr_xsk1lq2ylz7fhsn0dfmul2pe833cdwvjnvux9uaxuzaz50gs7pnmm9wq343uh5cpfs87tgh9saa86un8e2l266rsge0c5qsmtaud5r64ctndwkyth8q07fgusyr3fldhn6lgd5tat5cmcdzvfzhtd0cpsleuxg3sakhv", - addrXvk1: "addr_xvk1y3r70ejyadsaplez83p7uhy8p6l08a5sjl860kszevxu0jaxcwmx6avghwwqluj3eqg8zn7m0847smgh6hf3hs6ycj9wk6lsrplncvsxqj6wd", - paymentAddr0: "addr_test1vpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5eg57c2qv", - paymentAddr1: "addr_test1vq0a2lgc2e0r597dr983jrf5ns4hxz027u8n7wlcsjcw4ks96yjys", + mnemonic: "art forum devote street sure rather head chuckle guard poverty release quote oak craft enemy", + rootXsk: "root_xsk1hretan5mml3tq2p0twkhq4tz4jvka7m2l94kfr6yghkyfar6m9wppc7h9unw6p65y23kakzct3695rs32z7vaw3r2lg9scmfj8ec5du3ufydu5yuquxcz24jlkjhsc9vsa4ufzge9s00fn398svhacse5sh85djs", + addrXsk0: "addr_xsk1fzgcl9km0mve2jwe8qxve364w6te9vpddhwpw5g8wnjlupmmm9wxpdda6jaglx7smwl6qd5xuzjcweeq8ykp0wg9hng4pg6eumwx2t90swaed7ehsa6j86qsw3fnl4thtemsng6vukmz6ddf3cnd4sfkzu74xjqg", + addrXvk0: "addr_xvk1fz009r4f0aceaemksezlca9cz8p8rewhaurvyvgg2ndnq9vwj3w6lqamjman0pm4y05pqazn8l2hwhnhpx35eedk9566nr3xmtqnv9ccm4zyu", + addrXsk1: "addr_xsk1lq2ylz7fhsn0dfmul2pe833cdwvjnvux9uaxuzaz50gs7pnmm9wq343uh5cpfs87tgh9saa86un8e2l266rsge0c5qsmtaud5r64ctndwkyth8q07fgusyr3fldhn6lgd5tat5cmcdzvfzhtd0cpsleuxg3sakhv", + addrXvk1: "addr_xvk1y3r70ejyadsaplez83p7uhy8p6l08a5sjl860kszevxu0jaxcwmx6avghwwqluj3eqg8zn7m0847smgh6hf3hs6ycj9wk6lsrplncvsxqj6wd", + paymentBaseAddr0: "addr_test1qpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5ewvxwdrt70qlcpeeagscasafhffqsxy36t90ldv06wqrk2qum8x5w", + paymentEnterpriseAddr0: "addr_test1vpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5eg57c2qv", + paymentEnterpriseAddr1: "addr_test1vq0a2lgc2e0r597dr983jrf5ns4hxz027u8n7wlcsjcw4ks96yjys", + stakeAddr: "stake_test1urxr8x34l8s0uquu75gvwcw5m55sgrzga9jhlkk8a8qpm9q9p2w0s", }, // 18 words { - mnemonic: "churn shaft spoon second erode useless thrive burst group seed element sign scrub buffalo jelly grace neck useless", - rootXsk: "root_xsk1az4qjp85qunj75m8krdvdygmv6u4ceqj8vnwaf38wfd69ycksa0fwt7n0cfp5zwmht9u0j9dzxxnfssjmkh4vn3dwxvddsle6m2vkm8q8p7addwq8y7q3s3eekd3ate40rfr6rpjakctcn2p54cpr3kjmy2hdej2", - addrXsk0: "addr_xsk17zj2lhjk379klp40xfzsad0yzygqe45uaggnkzf4ld3emgsksa00ftq88fnfjxg245kjjqcukyjfg4lwmf3r2qqymyyqennch3y8llyg0d629pdx0pp0l69lerjz75kxmk5e6cr2d82kafp7a25y0qy5fvj06w0u", - addrXvk0: "addr_xvk1fwgdh5vv6akdc3rjpeq57xxq4lc9m84xcrt6q827mq7u20wuw54gs7m552z6v7zzll5tlj8y9afvdhdfn4sx56w4d6jra64gg7qfgjc8e8sau", - addrXsk1: "addr_xsk1wz99hznmt96crxthcmnxqttaul6caq4hv5jwttd5lly2mfsksa08q68skn2ggclu6vf40phx3wnj4e8fvxed6at8xxekwa49rg4c3ec8kp2nwcxfw6sgxphzckg5v0dausldvya0w6jy5k3cxwrqdjsthqls7zxn", - addrXvk1: "addr_xvk135hqmkaqydnxnq6wmjkkhasvwjprpnqnzsrwwes6mql45enlcsqs0vz4xasvja4qsvrw93v3gc7mmep76cf67a4yffdrsvuxqm9qhwqlvnay5", - paymentAddr0: "addr_test1vptvyjfjvs7wdn583rv3th3fvf9fauv5f6gylkhh5k245zcdjvdac", - paymentAddr1: "addr_test1vr3nq3kyg9c9t4nn6a5zymz3at3zsmcr9lkqxghxh5v822gcu7ava", + mnemonic: "churn shaft spoon second erode useless thrive burst group seed element sign scrub buffalo jelly grace neck useless", + rootXsk: "root_xsk1az4qjp85qunj75m8krdvdygmv6u4ceqj8vnwaf38wfd69ycksa0fwt7n0cfp5zwmht9u0j9dzxxnfssjmkh4vn3dwxvddsle6m2vkm8q8p7addwq8y7q3s3eekd3ate40rfr6rpjakctcn2p54cpr3kjmy2hdej2", + addrXsk0: "addr_xsk17zj2lhjk379klp40xfzsad0yzygqe45uaggnkzf4ld3emgsksa00ftq88fnfjxg245kjjqcukyjfg4lwmf3r2qqymyyqennch3y8llyg0d629pdx0pp0l69lerjz75kxmk5e6cr2d82kafp7a25y0qy5fvj06w0u", + addrXvk0: "addr_xvk1fwgdh5vv6akdc3rjpeq57xxq4lc9m84xcrt6q827mq7u20wuw54gs7m552z6v7zzll5tlj8y9afvdhdfn4sx56w4d6jra64gg7qfgjc8e8sau", + addrXsk1: "addr_xsk1wz99hznmt96crxthcmnxqttaul6caq4hv5jwttd5lly2mfsksa08q68skn2ggclu6vf40phx3wnj4e8fvxed6at8xxekwa49rg4c3ec8kp2nwcxfw6sgxphzckg5v0dausldvya0w6jy5k3cxwrqdjsthqls7zxn", + addrXvk1: "addr_xvk135hqmkaqydnxnq6wmjkkhasvwjprpnqnzsrwwes6mql45enlcsqs0vz4xasvja4qsvrw93v3gc7mmep76cf67a4yffdrsvuxqm9qhwqlvnay5", + paymentBaseAddr0: "addr_test1qptvyjfjvs7wdn583rv3th3fvf9fauv5f6gylkhh5k245zuv4te5ey3ksjyq3z0cq8k8pu57rek4qsvpxkc7gyzcnu5qzrtqf4", + paymentEnterpriseAddr0: "addr_test1vptvyjfjvs7wdn583rv3th3fvf9fauv5f6gylkhh5k245zcdjvdac", + paymentEnterpriseAddr1: "addr_test1vr3nq3kyg9c9t4nn6a5zymz3at3zsmcr9lkqxghxh5v822gcu7ava", + stakeAddr: "stake_test1uzx24u6vjgmgfzqg38uqrmrs720pum2sgxqntv0yzpvf72qhlmveq", }, // 21 words { - mnemonic: "draft ability female child jump maid roof hurt below live topple paper exclude ordinary coach churn sunset emerge blame ketchup much", - rootXsk: "root_xsk17zqw352yj02seytp9apunec55722k93crtplq8chgpfh7cx33dg4v2x3wpyhd9chhkknzhprztumrystkpfl5nyhyeuq0gnwf76r39u9l9q3z40hgf5jv6xn8unr5acs3yy8fxg35v5xjsw4kwvf5zfkvcn57fle", - addrXsk0: "addr_xsk1fz8tz0pdda8la0aqhadnzctw0p48zwygkgf4xyar2jjljm733dgkprs4sj8cxfwv9xtfddpdfvjlap0hhg9gd37pr0tp7ue48mh9cnfyy68k52f88z5vghezam30c3pcue6aewl4mqul6nvassxlenh3eqh822k2", - addrXvk0: "addr_xvk1x4dme9s2f5xxn77wgjhggqh73r6syy4nvjcdjklnaqrh48f6desjgf50dg5jww9gc30j9mhzl3zr3en4mjaltkpel4xempqdln80rjq5grmc7", - addrXsk1: "addr_xsk18peu0v64maghaa87jvu0txdkftvznq7he2yhntk8eem56mk33dgl2rwt8kmhcgdytr6fjn0t4cdf6sr3xud67yhwnjhzyghgu294f6v0fcfzqlactzd8cf5m4tpu7yyn5x58dx6q00d362j6e06g88phjglns3p5", - addrXvk1: "addr_xvk1ndtepmpg06x9nskfasvr50mue356e4rqlvuzf8jjcj6n48feexsg7nsjyplmsky60snfh2kreugf8gdgw6d5q77mr5494jl5swwr0ysprauul", - paymentAddr0: "addr_test1vz83dnlqqtdrlct4kz3f7d07d59w6p4yrtlr62340yklhaqrrykc7", - paymentAddr1: "addr_test1vzr08acccp7s3l9cppvptz7jyflejkkuma2k06vx4vjrcqsl4gkk5", + mnemonic: "draft ability female child jump maid roof hurt below live topple paper exclude ordinary coach churn sunset emerge blame ketchup much", + rootXsk: "root_xsk17zqw352yj02seytp9apunec55722k93crtplq8chgpfh7cx33dg4v2x3wpyhd9chhkknzhprztumrystkpfl5nyhyeuq0gnwf76r39u9l9q3z40hgf5jv6xn8unr5acs3yy8fxg35v5xjsw4kwvf5zfkvcn57fle", + addrXsk0: "addr_xsk1fz8tz0pdda8la0aqhadnzctw0p48zwygkgf4xyar2jjljm733dgkprs4sj8cxfwv9xtfddpdfvjlap0hhg9gd37pr0tp7ue48mh9cnfyy68k52f88z5vghezam30c3pcue6aewl4mqul6nvassxlenh3eqh822k2", + addrXvk0: "addr_xvk1x4dme9s2f5xxn77wgjhggqh73r6syy4nvjcdjklnaqrh48f6desjgf50dg5jww9gc30j9mhzl3zr3en4mjaltkpel4xempqdln80rjq5grmc7", + addrXsk1: "addr_xsk18peu0v64maghaa87jvu0txdkftvznq7he2yhntk8eem56mk33dgl2rwt8kmhcgdytr6fjn0t4cdf6sr3xud67yhwnjhzyghgu294f6v0fcfzqlactzd8cf5m4tpu7yyn5x58dx6q00d362j6e06g88phjglns3p5", + addrXvk1: "addr_xvk1ndtepmpg06x9nskfasvr50mue356e4rqlvuzf8jjcj6n48feexsg7nsjyplmsky60snfh2kreugf8gdgw6d5q77mr5494jl5swwr0ysprauul", + paymentBaseAddr0: "addr_test1qz83dnlqqtdrlct4kz3f7d07d59w6p4yrtlr62340yklhaxcd4azvtus2m6m3q409pnflcurpnkz3gnxf4ef47ducezsh8t7e5", + paymentEnterpriseAddr0: "addr_test1vz83dnlqqtdrlct4kz3f7d07d59w6p4yrtlr62340yklhaqrrykc7", + paymentEnterpriseAddr1: "addr_test1vzr08acccp7s3l9cppvptz7jyflejkkuma2k06vx4vjrcqsl4gkk5", + stakeAddr: "stake_test1urvx673x97g9dadcs2hjse5luwpsempg5fny6u56lx7vv3gpzreln", }, } @@ -70,6 +78,9 @@ func TestCreateWallet(t *testing.T) { if err != nil { t.Error(err) } + if mnemonic != testVector.mnemonic { + t.Errorf("invalid mnemonic:\ngot: %v\nwant: %v", mnemonic, testVector.mnemonic) + } addrXsk0 := bech32From("addr_xsk", w.addrKeys[0]) addrXvk0 := bech32From("addr_xvk", w.addrKeys[0].XPubKey()) @@ -82,17 +93,28 @@ func TestCreateWallet(t *testing.T) { t.Errorf("invalid addrXvk0 :\ngot: %v\nwant: %v", addrXvk0, testVector.addrXvk0) } - addresses, err := w.Addresses() + baseAddresses, err := w.BaseAddresses() if err != nil { t.Fatal(err) } + if baseAddresses[0].Bech32() != testVector.paymentBaseAddr0 { + t.Errorf("invalid paymentBaseAddr0:\ngot: %v\nwant: %v", baseAddresses[0], testVector.paymentBaseAddr0) + } - if mnemonic != testVector.mnemonic { - t.Errorf("invalid mnemonic:\ngot: %v\nwant: %v", mnemonic, testVector.mnemonic) + enterpriseAddresses, err := w.EnterpriseAddresses() + if err != nil { + t.Fatal(err) + } + if enterpriseAddresses[0].Bech32() != testVector.paymentEnterpriseAddr0 { + t.Errorf("invalid paymentEnterpriseAddr0:\ngot: %v\nwant: %v", enterpriseAddresses[0], testVector.paymentEnterpriseAddr0) } - if addresses[0].Bech32() != testVector.paymentAddr0 { - t.Errorf("invalid paymentAddr0:\ngot: %v\nwant: %v", addresses[0], testVector.paymentAddr0) + stakeAddr, err := w.StakeAddress() + if err != nil { + t.Fatal(err) + } + if stakeAddr.Bech32() != testVector.stakeAddr { + t.Errorf("invalid stakeAddr:\ngot: %v\nwant: %v", stakeAddr, testVector.stakeAddr) } } } @@ -122,9 +144,16 @@ func TestRestoreWallet(t *testing.T) { if err != nil { t.Fatal(err) } + if addresses[0].Bech32() != testVector.paymentEnterpriseAddr0 { + t.Errorf("invalid paymentEnterpriseAddr0:\ngot: %v\nwant: %v", addresses[0], testVector.paymentEnterpriseAddr0) + } - if addresses[0].Bech32() != testVector.paymentAddr0 { - t.Errorf("invalid paymentAddr0:\ngot: %v\nwant: %v", addresses[0], testVector.paymentAddr0) + stakeAddr, err := w.StakeAddress() + if err != nil { + t.Fatal(err) + } + if stakeAddr.Bech32() != testVector.stakeAddr { + t.Errorf("invalid stakeAddr:\ngot: %v\nwant: %v", stakeAddr, testVector.stakeAddr) } } } diff --git a/wallet/wallet.go b/wallet/wallet.go index f1a0695..1116edd 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -148,8 +148,29 @@ func (w *Wallet) AddAddress() (cardano.Address, error) { return cardano.NewEnterpriseAddress(w.network, payment) } -// Addresses returns all wallet's addresss. -func (w *Wallet) Addresses() ([]cardano.Address, error) { +// BaseAddresses returns all base addresses. +func (w *Wallet) BaseAddresses() ([]cardano.Address, error) { + addresses := make([]cardano.Address, len(w.addrKeys)) + for i, key := range w.addrKeys { + payment, err := cardano.NewKeyCredential(key.PubKey()) + if err != nil { + return nil, err + } + stake, err := cardano.NewKeyCredential(w.stakeKey.PubKey()) + if err != nil { + return nil, err + } + baseAddr, err := cardano.NewBaseAddress(w.network, payment, stake) + if err != nil { + return nil, err + } + addresses[i] = baseAddr + } + return addresses, nil +} + +// EnterpriseAddresses returns all enterprise addresses. +func (w *Wallet) EnterpriseAddresses() ([]cardano.Address, error) { addresses := make([]cardano.Address, len(w.addrKeys)) for i, key := range w.addrKeys { payment, err := cardano.NewKeyCredential(key.PubKey()) @@ -165,10 +186,30 @@ func (w *Wallet) Addresses() ([]cardano.Address, error) { return addresses, nil } -func (w *Wallet) Keys() (crypto.PrvKey, crypto.PrvKey) { +// Deprecated: replaced with EnterpriseAddresses() due to vague naming +// Addresses returns all wallet's addresss. +func (w *Wallet) Addresses() ([]cardano.Address, error) { + return w.EnterpriseAddresses() +} + +// StakeAddress returns wallet's stake address +func (w *Wallet) StakeAddress() (cardano.Address, error) { + stake, err := cardano.NewKeyCredential(w.stakeKey.PubKey()) + if err != nil { + return cardano.Address{}, err + } + return cardano.NewStakeAddress(w.network, stake) +} + +func (w *Wallet) PrvKeys() (crypto.PrvKey, crypto.PrvKey) { return w.addrKeys[0].PrvKey(), w.stakeKey.PrvKey() } +// Deprecated: replaced with PrvKeys() due to vague naming +func (w *Wallet) Keys() (crypto.PrvKey, crypto.PrvKey) { + return w.PrvKeys() +} + func newWalletID() string { id, _ := gonanoid.Generate(walleIDAlphabet, 10) return "wallet_" + id diff --git a/wallet/wallet_test.go b/wallet/wallet_test.go index f4005a6..7321dd4 100644 --- a/wallet/wallet_test.go +++ b/wallet/wallet_test.go @@ -42,8 +42,8 @@ func TestGenerateAddress(t *testing.T) { t.Errorf("invalid addrXvk1 :\ngot: %v\nwant: %v", addrXvk1, testVector.addrXvk1) } - if paymentAddr1.Bech32() != testVector.paymentAddr1 { - t.Errorf("invalid paymentAddr1:\ngot: %v\nwant: %v", paymentAddr1, testVector.paymentAddr1) + if paymentAddr1.Bech32() != testVector.paymentEnterpriseAddr1 { + t.Errorf("invalid paymentEnterpriseAddr1:\ngot: %v\nwant: %v", paymentAddr1, testVector.paymentEnterpriseAddr1) } } }