diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2b4c3323..91ecd39a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @loongy @jazg +@jazg @tok-kkk diff --git a/chain/kava/address.go b/chain/kava/address.go new file mode 100644 index 00000000..a914c987 --- /dev/null +++ b/chain/kava/address.go @@ -0,0 +1,33 @@ +package kava + +import ( + "github.com/renproject/multichain/chain/evm" +) + +type ( + // AddressEncodeDecoder re-exports evm.AddressEncodeDecoder. + AddressEncodeDecoder = evm.AddressEncodeDecoder + + // AddressEncoder re-exports evm.AddressEncoder. + AddressEncoder = evm.AddressEncoder + + // AddressDecoder re-exports evm.AddressDecoder. + AddressDecoder = evm.AddressDecoder + + // Address re-exports evm.Address. + Address = evm.Address +) + +var ( + // NewAddressEncodeDecoder re-exports evm.NewAddressEncodeDecoder. + NewAddressEncodeDecoder = evm.NewAddressEncodeDecoder + + // NewAddressDecoder re-exports evm.NewAddressDecoder. + NewAddressDecoder = evm.NewAddressDecoder + + // NewAddressEncoder re-exports evm.NewAddressEncoder. + NewAddressEncoder = evm.NewAddressEncoder + + // NewAddressFromHex re-exports evm.NewAddressFromHex. + NewAddressFromHex = evm.NewAddressFromHex +) diff --git a/chain/kava/address_test.go b/chain/kava/address_test.go new file mode 100644 index 00000000..3a39e549 --- /dev/null +++ b/chain/kava/address_test.go @@ -0,0 +1,107 @@ +package kava_test + +import ( + "encoding/hex" + "encoding/json" + "testing/quick" + + "github.com/renproject/multichain/chain/kava" + "github.com/renproject/surge" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Address", func() { + Context("when unmarshaling and unmarshaling", func() { + It("should equal itself", func() { + f := func(x [20]byte) bool { + addr := kava.Address(x) + Expect(addr.SizeHint()).To(Equal(20)) + + bytes, err := surge.ToBinary(addr) + Expect(err).ToNot(HaveOccurred()) + + var newAddr kava.Address + err = surge.FromBinary(&newAddr, bytes) + Expect(err).ToNot(HaveOccurred()) + + Expect(addr).To(Equal(newAddr)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when unmarshaling and unmarshaling to/from JSON", func() { + It("should equal itself", func() { + f := func(x [20]byte) bool { + addr := kava.Address(x) + + bytes, err := json.Marshal(addr) + Expect(err).ToNot(HaveOccurred()) + + var newAddr kava.Address + err = json.Unmarshal(bytes, &newAddr) + Expect(err).ToNot(HaveOccurred()) + + Expect(addr).To(Equal(newAddr)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("when the address is invalid hex", func() { + It("should return an error", func() { + f := func(x [40]byte) bool { + bytes, err := json.Marshal(string(x[:])) + Expect(err).ToNot(HaveOccurred()) + + var newAddr kava.Address + err = json.Unmarshal(bytes, &newAddr) + Expect(err).To(HaveOccurred()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when the address is invalid length", func() { + It("should return an error", func() { + f := func(x [10]byte) bool { + addr := hex.EncodeToString(x[:]) + bytes, err := json.Marshal(addr) + Expect(err).ToNot(HaveOccurred()) + + var newAddr kava.Address + err = json.Unmarshal(bytes, &newAddr) + Expect(err).To(HaveOccurred()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + }) + + Context("when unmarshalling random data", func() { + It("should not panic", func() { + f := func(x []byte) bool { + var addr kava.Address + Expect(func() { addr.Unmarshal(x, surge.MaxBytes) }).ToNot(Panic()) + Expect(func() { json.Unmarshal(x, &addr) }).ToNot(Panic()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) +}) diff --git a/chain/kava/client.go b/chain/kava/client.go new file mode 100644 index 00000000..fcc3ee65 --- /dev/null +++ b/chain/kava/client.go @@ -0,0 +1,17 @@ +package kava + +import ( + "github.com/renproject/multichain/chain/evm" +) + +const ( + // DefaultClientRPCURL is the RPC URL used by default, to interact with the + // bsc node. + DefaultClientRPCURL = "http://127.0.0.1:8575/" +) + +// Client re-exports evm.Client. +type Client = evm.Client + +// NewClient re-exports evm.NewClient. +var NewClient = evm.NewClient diff --git a/chain/kava/encode.go b/chain/kava/encode.go new file mode 100644 index 00000000..cbaf835a --- /dev/null +++ b/chain/kava/encode.go @@ -0,0 +1,11 @@ +package kava + +import ( + "github.com/renproject/multichain/chain/evm" +) + +// Payload re-exports evm.Payload. +type Payload = evm.Payload + +// Encode re-exports evm.Encode. +var Encode = evm.Encode diff --git a/chain/kava/encode_test.go b/chain/kava/encode_test.go new file mode 100644 index 00000000..bc3ab871 --- /dev/null +++ b/chain/kava/encode_test.go @@ -0,0 +1,255 @@ +package kava_test + +import ( + "encoding/hex" + "fmt" + "math" + "testing/quick" + + "github.com/renproject/multichain/chain/kava" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" +) + +var _ = Describe("Encoding", func() { + Context("when encoding bytes", func() { + It("should return the correct result", func() { + f := func(x []byte) bool { + arg := pack.NewBytes(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + + expectedBytes := make([]byte, int(math.Ceil(float64(len(x))/32)*32)) + copy(expectedBytes, x) + // Note: since the first parameter has a dynamic length, the + // first 32 bytes instead contain a pointer to the data. + expectedString := fmt.Sprintf("%064x", 32) + fmt.Sprintf("%064x", len(x)) + hex.EncodeToString(expectedBytes) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 32 bytes", func() { + It("should return the correct result", func() { + f := func(x [32]byte) bool { + arg := pack.NewBytes32(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := hex.EncodeToString(x[:]) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 8-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint8) bool { + arg := pack.NewU8(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 16-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint16) bool { + arg := pack.NewU16(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 32-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint32) bool { + arg := pack.NewU32(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 64-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint64) bool { + arg := pack.NewU64(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 128-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x [16]byte) bool { + arg := pack.NewU128(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 256-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x [32]byte) bool { + arg := pack.NewU256(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding Ethereum addresses", func() { + It("should return the correct result", func() { + f := func(x [20]byte) bool { + arg := kava.Address(x) + + resBytes := kava.Encode(arg) + resString := hex.EncodeToString(resBytes) + + expectedBytes := make([]byte, 32) + copy(expectedBytes, x[:]) + expectedString := hex.EncodeToString(expectedBytes) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding an unsupported type", func() { + It("should panic", func() { + f := func(x bool) bool { + arg := pack.NewBool(x) + Expect(func() { kava.Encode(arg) }).To(Panic()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + type testCase struct { + addr string + amount uint64 + hash string + result string + } + + testCases := []testCase{ + { + addr: "797522Fb74d42bB9fbF6b76dEa24D01A538d5D66", + amount: 10000, + hash: "702826c3977ee72158db2ce1fb758075ee2799db65fb27b5d0952f860a8084ed", + result: "797522fb74d42bb9fbf6b76dea24d01a538d5d660000000000000000000000000000000000000000000000000000000000000000000000000000000000002710702826c3977ee72158db2ce1fb758075ee2799db65fb27b5d0952f860a8084ed", + }, + { + addr: "58afb504ef2444a267b8c7ce57279417f1377ceb", + amount: 50000000000000000, + hash: "dabff9ceb1b3dabb696d143326fdb98a8c7deb260e65d08a294b16659d573f93", + result: "58afb504ef2444a267b8c7ce57279417f1377ceb00000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec50000dabff9ceb1b3dabb696d143326fdb98a8c7deb260e65d08a294b16659d573f93", + }, + { + addr: "0000000000000000000000000000000000000000", + amount: 0, + hash: "0000000000000000000000000000000000000000000000000000000000000000", + result: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + } + + DescribeTable("when encoding args", + func(test testCase) { + addrBytes, err := hex.DecodeString(test.addr) + Expect(err).ToNot(HaveOccurred()) + + var addr kava.Address + copy(addr[:], addrBytes) + + hashBytes32 := [32]byte{} + hashBytes, err := hex.DecodeString(test.hash) + Expect(err).ToNot(HaveOccurred()) + copy(hashBytes32[:], hashBytes) + + args := []interface{}{ + addr, + pack.NewU64(test.amount), + pack.NewBytes32(hashBytes32), + } + result := kava.Encode(args...) + Expect(hex.EncodeToString(result)).To(Equal(test.result)) + }, + + Entry("should return the same result as solidity for small transactions", testCases[0]), + Entry("should return the same result as solidity for large transactions", testCases[1]), + Entry("should return the same result as solidity for empty transactions", testCases[2]), + ) +}) diff --git a/chain/kava/gas.go b/chain/kava/gas.go new file mode 100644 index 00000000..10ed62fd --- /dev/null +++ b/chain/kava/gas.go @@ -0,0 +1,11 @@ +package kava + +import ( + "github.com/renproject/multichain/chain/evm" +) + +// GasEstimator re-exports evm.GasEstimator. +type GasEstimator = evm.GasEstimator + +// NewGasEstimator re-exports evm.NewGasEstimator. +var NewGasEstimator = evm.NewGasEstimator diff --git a/chain/kava/tx.go b/chain/kava/tx.go new file mode 100644 index 00000000..be488066 --- /dev/null +++ b/chain/kava/tx.go @@ -0,0 +1,16 @@ +package kava + +import ( + "github.com/renproject/multichain/chain/evm" +) + +type ( + // TxBuilder re-exports evm.TxBuilder. + TxBuilder = evm.TxBuilder + + // Tx re-exports evm.Tx. + Tx = evm.Tx +) + +// NewTxBuilder re-exports evm.NewTxBuilder. +var NewTxBuilder = evm.NewTxBuilder diff --git a/chain/moonbeam/address.go b/chain/moonbeam/address.go new file mode 100644 index 00000000..3d987ef1 --- /dev/null +++ b/chain/moonbeam/address.go @@ -0,0 +1,33 @@ +package moonbeam + +import ( + "github.com/renproject/multichain/chain/evm" +) + +type ( + // AddressEncodeDecoder re-exports evm.AddressEncodeDecoder. + AddressEncodeDecoder = evm.AddressEncodeDecoder + + // AddressEncoder re-exports evm.AddressEncoder. + AddressEncoder = evm.AddressEncoder + + // AddressDecoder re-exports evm.AddressDecoder. + AddressDecoder = evm.AddressDecoder + + // Address re-exports evm.Address. + Address = evm.Address +) + +var ( + // NewAddressEncodeDecoder re-exports evm.NewAddressEncodeDecoder. + NewAddressEncodeDecoder = evm.NewAddressEncodeDecoder + + // NewAddressDecoder re-exports evm.NewAddressDecoder. + NewAddressDecoder = evm.NewAddressDecoder + + // NewAddressEncoder re-exports evm.NewAddressEncoder. + NewAddressEncoder = evm.NewAddressEncoder + + // NewAddressFromHex re-exports evm.NewAddressFromHex. + NewAddressFromHex = evm.NewAddressFromHex +) diff --git a/chain/moonbeam/address_test.go b/chain/moonbeam/address_test.go new file mode 100644 index 00000000..f42151b9 --- /dev/null +++ b/chain/moonbeam/address_test.go @@ -0,0 +1,107 @@ +package moonbeam_test + +import ( + "encoding/hex" + "encoding/json" + "testing/quick" + + "github.com/renproject/multichain/chain/moonbeam" + "github.com/renproject/surge" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Address", func() { + Context("when unmarshaling and unmarshaling", func() { + It("should equal itself", func() { + f := func(x [20]byte) bool { + addr := moonbeam.Address(x) + Expect(addr.SizeHint()).To(Equal(20)) + + bytes, err := surge.ToBinary(addr) + Expect(err).ToNot(HaveOccurred()) + + var newAddr moonbeam.Address + err = surge.FromBinary(&newAddr, bytes) + Expect(err).ToNot(HaveOccurred()) + + Expect(addr).To(Equal(newAddr)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when unmarshaling and unmarshaling to/from JSON", func() { + It("should equal itself", func() { + f := func(x [20]byte) bool { + addr := moonbeam.Address(x) + + bytes, err := json.Marshal(addr) + Expect(err).ToNot(HaveOccurred()) + + var newAddr moonbeam.Address + err = json.Unmarshal(bytes, &newAddr) + Expect(err).ToNot(HaveOccurred()) + + Expect(addr).To(Equal(newAddr)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("when the address is invalid hex", func() { + It("should return an error", func() { + f := func(x [40]byte) bool { + bytes, err := json.Marshal(string(x[:])) + Expect(err).ToNot(HaveOccurred()) + + var newAddr moonbeam.Address + err = json.Unmarshal(bytes, &newAddr) + Expect(err).To(HaveOccurred()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when the address is invalid length", func() { + It("should return an error", func() { + f := func(x [10]byte) bool { + addr := hex.EncodeToString(x[:]) + bytes, err := json.Marshal(addr) + Expect(err).ToNot(HaveOccurred()) + + var newAddr moonbeam.Address + err = json.Unmarshal(bytes, &newAddr) + Expect(err).To(HaveOccurred()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + }) + + Context("when unmarshalling random data", func() { + It("should not panic", func() { + f := func(x []byte) bool { + var addr moonbeam.Address + Expect(func() { addr.Unmarshal(x, surge.MaxBytes) }).ToNot(Panic()) + Expect(func() { json.Unmarshal(x, &addr) }).ToNot(Panic()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) +}) diff --git a/chain/moonbeam/client.go b/chain/moonbeam/client.go new file mode 100644 index 00000000..a7df6822 --- /dev/null +++ b/chain/moonbeam/client.go @@ -0,0 +1,17 @@ +package moonbeam + +import ( + "github.com/renproject/multichain/chain/evm" +) + +const ( + // DefaultClientRPCURL is the RPC URL used by default, to interact with the + // bsc node. + DefaultClientRPCURL = "http://127.0.0.1:8575/" +) + +// Client re-exports evm.Client. +type Client = evm.Client + +// NewClient re-exports evm.NewClient. +var NewClient = evm.NewClient diff --git a/chain/moonbeam/encode.go b/chain/moonbeam/encode.go new file mode 100644 index 00000000..269109d1 --- /dev/null +++ b/chain/moonbeam/encode.go @@ -0,0 +1,11 @@ +package moonbeam + +import ( + "github.com/renproject/multichain/chain/evm" +) + +// Payload re-exports evm.Payload. +type Payload = evm.Payload + +// Encode re-exports evm.Encode. +var Encode = evm.Encode diff --git a/chain/moonbeam/encode_test.go b/chain/moonbeam/encode_test.go new file mode 100644 index 00000000..c2035daf --- /dev/null +++ b/chain/moonbeam/encode_test.go @@ -0,0 +1,255 @@ +package moonbeam_test + +import ( + "encoding/hex" + "fmt" + "math" + "testing/quick" + + "github.com/renproject/multichain/chain/moonbeam" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" +) + +var _ = Describe("Encoding", func() { + Context("when encoding bytes", func() { + It("should return the correct result", func() { + f := func(x []byte) bool { + arg := pack.NewBytes(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + + expectedBytes := make([]byte, int(math.Ceil(float64(len(x))/32)*32)) + copy(expectedBytes, x) + // Note: since the first parameter has a dynamic length, the + // first 32 bytes instead contain a pointer to the data. + expectedString := fmt.Sprintf("%064x", 32) + fmt.Sprintf("%064x", len(x)) + hex.EncodeToString(expectedBytes) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 32 bytes", func() { + It("should return the correct result", func() { + f := func(x [32]byte) bool { + arg := pack.NewBytes32(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := hex.EncodeToString(x[:]) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 8-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint8) bool { + arg := pack.NewU8(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 16-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint16) bool { + arg := pack.NewU16(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 32-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint32) bool { + arg := pack.NewU32(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 64-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x uint64) bool { + arg := pack.NewU64(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 128-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x [16]byte) bool { + arg := pack.NewU128(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding 256-bit unsigned integers", func() { + It("should return the correct result", func() { + f := func(x [32]byte) bool { + arg := pack.NewU256(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + expectedString := fmt.Sprintf("%064x", x) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding Ethereum addresses", func() { + It("should return the correct result", func() { + f := func(x [20]byte) bool { + arg := moonbeam.Address(x) + + resBytes := moonbeam.Encode(arg) + resString := hex.EncodeToString(resBytes) + + expectedBytes := make([]byte, 32) + copy(expectedBytes, x[:]) + expectedString := hex.EncodeToString(expectedBytes) + + Expect(resString).To(Equal(expectedString)) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when encoding an unsupported type", func() { + It("should panic", func() { + f := func(x bool) bool { + arg := pack.NewBool(x) + Expect(func() { moonbeam.Encode(arg) }).To(Panic()) + return true + } + + err := quick.Check(f, nil) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + type testCase struct { + addr string + amount uint64 + hash string + result string + } + + testCases := []testCase{ + { + addr: "797522Fb74d42bB9fbF6b76dEa24D01A538d5D66", + amount: 10000, + hash: "702826c3977ee72158db2ce1fb758075ee2799db65fb27b5d0952f860a8084ed", + result: "797522fb74d42bb9fbf6b76dea24d01a538d5d660000000000000000000000000000000000000000000000000000000000000000000000000000000000002710702826c3977ee72158db2ce1fb758075ee2799db65fb27b5d0952f860a8084ed", + }, + { + addr: "58afb504ef2444a267b8c7ce57279417f1377ceb", + amount: 50000000000000000, + hash: "dabff9ceb1b3dabb696d143326fdb98a8c7deb260e65d08a294b16659d573f93", + result: "58afb504ef2444a267b8c7ce57279417f1377ceb00000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec50000dabff9ceb1b3dabb696d143326fdb98a8c7deb260e65d08a294b16659d573f93", + }, + { + addr: "0000000000000000000000000000000000000000", + amount: 0, + hash: "0000000000000000000000000000000000000000000000000000000000000000", + result: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + } + + DescribeTable("when encoding args", + func(test testCase) { + addrBytes, err := hex.DecodeString(test.addr) + Expect(err).ToNot(HaveOccurred()) + + var addr moonbeam.Address + copy(addr[:], addrBytes) + + hashBytes32 := [32]byte{} + hashBytes, err := hex.DecodeString(test.hash) + Expect(err).ToNot(HaveOccurred()) + copy(hashBytes32[:], hashBytes) + + args := []interface{}{ + addr, + pack.NewU64(test.amount), + pack.NewBytes32(hashBytes32), + } + result := moonbeam.Encode(args...) + Expect(hex.EncodeToString(result)).To(Equal(test.result)) + }, + + Entry("should return the same result as solidity for small transactions", testCases[0]), + Entry("should return the same result as solidity for large transactions", testCases[1]), + Entry("should return the same result as solidity for empty transactions", testCases[2]), + ) +}) diff --git a/chain/moonbeam/gas.go b/chain/moonbeam/gas.go new file mode 100644 index 00000000..32332cee --- /dev/null +++ b/chain/moonbeam/gas.go @@ -0,0 +1,11 @@ +package moonbeam + +import ( + "github.com/renproject/multichain/chain/evm" +) + +// GasEstimator re-exports evm.GasEstimator. +type GasEstimator = evm.GasEstimator + +// NewGasEstimator re-exports evm.NewGasEstimator. +var NewGasEstimator = evm.NewGasEstimator diff --git a/chain/moonbeam/tx.go b/chain/moonbeam/tx.go new file mode 100644 index 00000000..36c25224 --- /dev/null +++ b/chain/moonbeam/tx.go @@ -0,0 +1,16 @@ +package moonbeam + +import ( + "github.com/renproject/multichain/chain/evm" +) + +type ( + // TxBuilder re-exports evm.TxBuilder. + TxBuilder = evm.TxBuilder + + // Tx re-exports evm.Tx. + Tx = evm.Tx +) + +// NewTxBuilder re-exports evm.NewTxBuilder. +var NewTxBuilder = evm.NewTxBuilder diff --git a/infra/zcash/Dockerfile b/infra/zcash/Dockerfile index 8d14df3b..f1518f7b 100644 --- a/infra/zcash/Dockerfile +++ b/infra/zcash/Dockerfile @@ -1,10 +1,10 @@ -FROM ubuntu:bionic +FROM debian:buster # Install zcashd. RUN apt-get update && \ apt-get install -y --no-install-recommends apt-transport-https gnupg2 ca-certificates wget && \ wget -qO - https://apt.z.cash/zcash.asc | apt-key add - && \ - echo "deb [arch=amd64] https://apt.z.cash/ stretch main" | tee /etc/apt/sources.list.d/zcash.list && \ + echo "deb [arch=amd64] https://apt.z.cash/ buster main" | tee /etc/apt/sources.list.d/zcash.list && \ apt-get update && apt-get install -y --no-install-recommends zcash && \ mkdir -p /root/.zcash-params && zcash-fetch-params diff --git a/multichain.go b/multichain.go index 0faf5141..ed30d22a 100644 --- a/multichain.go +++ b/multichain.go @@ -110,6 +110,7 @@ const ( FIL = Asset("FIL") // Filecoin FTM = Asset("FTM") // Fantom GLMR = Asset("GLMR") // Glimmer + KAVA = Asset("KAVA") // Kava LUNA = Asset("LUNA") // Luna MATIC = Asset("MATIC") // Matic PoS (Polygon) SOL = Asset("SOL") // Solana @@ -207,6 +208,8 @@ func (asset Asset) OriginChain() Chain { return Fantom case GLMR: return Moonbeam + case KAVA: + return Kava case LUNA: return Terra case MATIC: @@ -245,7 +248,7 @@ func (asset Asset) ChainType() ChainType { switch asset { case BCH, BTC, DGB, DOGE, ZEC: return ChainTypeUTXOBased - case ArbETH, AVAX, BNB, ETH, FIL, FTM, GLMR, LUNA, MATIC, SOL: + case ArbETH, AVAX, BNB, ETH, FIL, FTM, GLMR, KAVA, LUNA, MATIC, SOL: return ChainTypeAccountBased case BADGER, BUSD, CRV, DAI, EURT, FTT, ibBTC, KNC, LINK, MIM, REN, ROOK, @@ -271,7 +274,7 @@ func (asset Asset) ChainType() ChainType { // Type returns the asset-type (Native or Token) for the given asset. func (asset Asset) Type() AssetType { switch asset { - case ArbETH, AVAX, BNB, ETH, FTM, GLMR, MATIC, SOL: + case ArbETH, AVAX, BNB, ETH, FTM, GLMR, KAVA, MATIC, SOL: return AssetTypeNative case BADGER, BUSD, CRV, DAI, EURT, FTT, ibBTC, KNC, LINK, MIM, REN, ROOK, @@ -327,8 +330,10 @@ const ( Ethereum = Chain("Ethereum") Fantom = Chain("Fantom") Filecoin = Chain("Filecoin") + Kava = Chain("Kava") Moonbeam = Chain("Moonbeam") Polygon = Chain("Polygon") + Ren = Chain("Ren") Solana = Chain("Solana") Terra = Chain("Terra") Zcash = Chain("Zcash") @@ -368,7 +373,8 @@ func (chain Chain) ChainType() ChainType { switch chain { case Bitcoin, BitcoinCash, DigiByte, Dogecoin, Zcash: return ChainTypeUTXOBased - case Avalanche, BinanceSmartChain, Ethereum, Arbitrum, Fantom, Filecoin, Moonbeam, Polygon, Solana, Terra: + case Avalanche, BinanceSmartChain, Ethereum, Arbitrum, Fantom, Filecoin, + Kava, Moonbeam, Polygon, Ren, Solana, Terra: return ChainTypeAccountBased case Kovan, Goerli: @@ -421,6 +427,8 @@ func (chain Chain) NativeAsset() Asset { return FTM case Filecoin: return FIL + case Kava: + return KAVA case Moonbeam: return GLMR case Polygon: