diff --git a/Makefile b/Makefile index 70b5168..5308bd7 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,15 @@ .PHONY: all generate binary test lint -CGO_LDFLAGS="-L$(CURDIR) -lm" - all: binary -libzks-crypto.a: - rm -f libzks-crypto.so # remove the dynamic library if it exists - wget https://github.com/zksync-sdk/zksync-crypto-c/releases/download/v0.1.2/zks-crypto-x86_64-unknown-linux-gnu.a -O $(CURDIR)/libzks-crypto.a - generate: go generate ./... -binary: libzks-crypto.a - CGO_LDFLAGS=$(CGO_LDFLAGS) go build ./cmd/crybapy +binary: + go build ./cmd/crybapy -test: libzks-crypto.a - CGO_LDFLAGS=$(CGO_LDFLAGS) go test -race ./... +test: + go test -race ./... lint: docker run --rm -v $(CURDIR):/app -v $(HOME)/.cache/golangci-lint/v1.59.1:/root/.cache -w /app golangci/golangci-lint:v1.59.1 golangci-lint run -v diff --git a/cmd/crybapy/factory_payer.go b/cmd/crybapy/factory_payer.go index c36bea6..c9c25e5 100644 --- a/cmd/crybapy/factory_payer.go +++ b/cmd/crybapy/factory_payer.go @@ -14,7 +14,6 @@ import ( "storj.io/crypto-batch-payment/pkg/eth" "storj.io/crypto-batch-payment/pkg/payer" "storj.io/crypto-batch-payment/pkg/storjtoken" - "storj.io/crypto-batch-payment/pkg/zksync" "storj.io/crypto-batch-payment/pkg/zksyncera" ) @@ -161,28 +160,6 @@ func CreatePayer(ctx context.Context, log *zap.Logger, config PayerConfig, nodeA if err != nil { return nil, errs.Wrap(err) } - case payer.ZkSync: - paymentPayer, err = zksync.NewPayer( - ctx, - nodeAddress, - spenderKey, - int(chainID.Int64()), - false, - maxFee) - if err != nil { - return nil, errs.Wrap(err) - } - case payer.ZkWithdraw: - paymentPayer, err = zksync.NewPayer( - ctx, - nodeAddress, - spenderKey, - int(chainID.Int64()), - true, - maxFee) - if err != nil { - return nil, errs.Wrap(err) - } case payer.ZkSyncEra: var paymasterAddress *common.Address var paymasterPayload []byte diff --git a/go.mod b/go.mod index 44bd14a..3e5d66c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/stretchr/testify v1.9.0 github.com/zeebo/errs v1.2.2 github.com/zeebo/errs/v2 v2.0.3 - github.com/zksync-sdk/zksync-sdk-go v0.0.0-20211119083613-58613b4d3d77 github.com/zksync-sdk/zksync2-go v0.4.0 go.uber.org/zap v1.16.0 golang.org/x/exp v0.0.0-20240213143201-ec583247a57a diff --git a/go.sum b/go.sum index aa1c13e..e93ebdc 100644 --- a/go.sum +++ b/go.sum @@ -560,8 +560,6 @@ github.com/zeebo/errs v1.2.2 h1:5NFypMTuSdoySVTqlNs1dEoU21QVamMQJxW/Fii5O7g= github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zeebo/errs/v2 v2.0.3 h1:WwqAmopgot4ZC+CgIveP+H91Nf78NDEGWjtAXen45Hw= github.com/zeebo/errs/v2 v2.0.3/go.mod h1:OKmvVZt4UqpyJrYFykDKm168ZquJ55pbbIVUICNmLN0= -github.com/zksync-sdk/zksync-sdk-go v0.0.0-20211119083613-58613b4d3d77 h1:qcdE1F/TnY4Kck5Uy9SO6avKVcQ53vgFZeuQ4G7jfGk= -github.com/zksync-sdk/zksync-sdk-go v0.0.0-20211119083613-58613b4d3d77/go.mod h1:ZUgHa5wGdUAYfBlO6iEL3UV/IVTiKNI4JuWlLnbBpWM= github.com/zksync-sdk/zksync2-go v0.4.0 h1:gfV3EQWNXkcUkdRwzMqJ4Zh/RNHnOIXrD4qsipUV4OY= github.com/zksync-sdk/zksync2-go v0.4.0/go.mod h1:V0lqO7C20wJDHz+r4o/NFoomCMD0lOjT26EZ4njjwmc= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= diff --git a/pkg/config/config.go b/pkg/config/config.go index 09e748c..7c63546 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -18,7 +18,6 @@ type Config struct { Pipeline Pipeline `toml:"pipeline"` CoinMarketCap CoinMarketCap `toml:"coinmarketcap"` Eth *Eth `toml:"eth"` - ZkSync *ZkSync `toml:"zksync"` ZkSyncEra *ZkSyncEra `toml:"zksync-era"` } @@ -38,14 +37,6 @@ func (c *Config) NewPayers(ctx context.Context) (_ Payers, err error) { payers.Add(payer.Eth, p) } - if c.ZkSync != nil { - p, err := c.ZkSync.NewPayer(ctx) - if err != nil { - return nil, fmt.Errorf("failed to init zksync payer: %w", err) - } - payers.Add(payer.ZkSync, p) - } - if c.ZkSyncEra != nil { p, err := c.ZkSyncEra.NewPayer(ctx) if err != nil { @@ -73,14 +64,6 @@ func (c *Config) NewAuditors(ctx context.Context) (_ Auditors, err error) { auditors.Add(payer.Eth, p) } - if c.ZkSync != nil { - p, err := c.ZkSync.NewAuditor(ctx) - if err != nil { - return nil, fmt.Errorf("failed to init zksync auditor: %w", err) - } - auditors.Add(payer.ZkSync, p) - } - if c.ZkSyncEra != nil { p, err := c.ZkSyncEra.NewAuditor(ctx) if err != nil { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 415481c..dd0ad28 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -44,12 +44,6 @@ func TestLoad_Defaults(t *testing.T) { MaxGas: nil, GasTipCap: nil, }, - ZkSync: &config.ZkSync{ - NodeAddress: "https://api.zksync.io", - SpenderKeyPath: homePath("some.key"), - ChainID: 0, - MaxFee: nil, - }, ZkSyncEra: &config.ZkSyncEra{ NodeAddress: "https://mainnet.era.zksync.io", SpenderKeyPath: homePath("some.key"), @@ -85,12 +79,6 @@ func TestLoad_Overrides(t *testing.T) { MaxGas: big.NewInt(80_000_000_000), GasTipCap: big.NewInt(2_000_000_000), }, - ZkSync: &config.ZkSync{ - NodeAddress: "https://override.test", - SpenderKeyPath: "override", - ChainID: 12345, - MaxFee: big.NewInt(1234), - }, ZkSyncEra: &config.ZkSyncEra{ NodeAddress: "https://override.test", SpenderKeyPath: "override", diff --git a/pkg/config/testdata/defaults.toml b/pkg/config/testdata/defaults.toml index de7e1fa..d600f1e 100644 --- a/pkg/config/testdata/defaults.toml +++ b/pkg/config/testdata/defaults.toml @@ -15,11 +15,6 @@ erc20_contract_address = "0x1111111111111111111111111111111111111111" # max_gas = "70_000_000_000" # gas_tip_cap = "1_000_000_000" -[zksync] -node_address = "https://api.zksync.io" -spender_key_path = "~/some.key" -# max_fee = "" - [zksync-era] node_address = "https://mainnet.era.zksync.io" spender_key_path = "~/some.key" diff --git a/pkg/config/testdata/override.toml b/pkg/config/testdata/override.toml index d8c7b6c..775034f 100644 --- a/pkg/config/testdata/override.toml +++ b/pkg/config/testdata/override.toml @@ -16,12 +16,6 @@ owner = "0xe66652d41EE7e81d3fcAe1dF7F9B9f9411ac835e" max_gas = "80_000_000_000" gas_tip_cap = "2_000_000_000" -[zksync] -node_address = "https://override.test" -spender_key_path = "override" -chain_id = 12345 -max_fee = "1234" - [zksync-era] node_address = "https://override.test" spender_key_path = "override" diff --git a/pkg/config/zksync.go b/pkg/config/zksync.go deleted file mode 100644 index 8736a0d..0000000 --- a/pkg/config/zksync.go +++ /dev/null @@ -1,71 +0,0 @@ -package config - -import ( - "context" - "errors" - "math/big" - - "github.com/zeebo/errs" - - "storj.io/crypto-batch-payment/pkg/zksync" -) - -type ZkSync struct { - NodeAddress string `toml:"node_address"` - SpenderKeyPath Path `toml:"spender_key_path"` - ChainID int `toml:"chain_id"` - MaxFee *big.Int `toml:"max_fee"` -} - -func (c ZkSync) NewPayer(ctx context.Context) (_ Payer, err error) { - // Check for required parameters - if c.NodeAddress == "" { - return nil, errors.New("zksync node_address is not configured") - } - - // Apply defaults - if c.ChainID == 0 { - c.ChainID = defaultEthChainID - } - - spenderKey, _, err := loadSpenderKey(string(c.SpenderKeyPath)) - if err != nil { - return nil, err - } - - zkPayer, err := zksync.NewPayer( - ctx, - c.NodeAddress, - spenderKey, - c.ChainID, - false, - c.MaxFee) - if err != nil { - return nil, errs.Wrap(err) - } - - return &payerWrapper{ - Payer: zkPayer, - }, nil -} - -func (c ZkSync) NewAuditor(ctx context.Context) (_ Auditor, err error) { - // Check for required parameters - if c.NodeAddress == "" { - return nil, errors.New("zksync node_address is not configured") - } - - // Apply defaults - if c.ChainID == 0 { - c.ChainID = defaultEthChainID - } - - zkAuditor, err := zksync.NewAuditor(c.NodeAddress, c.ChainID) - if err != nil { - return nil, errs.Wrap(err) - } - - return &auditorWrapper{ - Auditor: zkAuditor, - }, nil -} diff --git a/pkg/payer/types.go b/pkg/payer/types.go index 92aad92..d875e65 100644 --- a/pkg/payer/types.go +++ b/pkg/payer/types.go @@ -10,12 +10,10 @@ import ( type Type string const ( - Eth Type = "eth" - Sim Type = "sim" - ZkSync Type = "zksync" - ZkSyncEra Type = "zksync-era" - ZkWithdraw Type = "zkwithdraw" - Polygon Type = "polygon" + Eth Type = "eth" + Sim Type = "sim" + ZkSyncEra Type = "zksync-era" + Polygon Type = "polygon" ) func (pt Type) String() string { @@ -29,12 +27,8 @@ func TypeFromString(t string) (Type, error) { return Eth, nil case "polygon": return Polygon, nil - case "zksync": - return ZkSync, nil case "zksync-era", "zksync2": // zksync2 for backcompat return ZkSyncEra, nil - case "zkwithdraw": - return ZkWithdraw, nil case "sim": return Sim, nil default: diff --git a/pkg/payouts/audit.go b/pkg/payouts/audit.go index 819e3f4..b75207a 100644 --- a/pkg/payouts/audit.go +++ b/pkg/payouts/audit.go @@ -12,7 +12,6 @@ import ( "storj.io/crypto-batch-payment/pkg/payer" "storj.io/crypto-batch-payment/pkg/pipelinedb" "storj.io/crypto-batch-payment/pkg/receipts" - "storj.io/crypto-batch-payment/pkg/zksync" "storj.io/crypto-batch-payment/pkg/zksyncera" "storj.io/crypto-batch-payment/pkg/csv" @@ -54,14 +53,6 @@ func Audit(ctx context.Context, dir string, csvPath string, payerType payer.Type } case payer.Sim: auditor = payer.NewSimAuditor() - case payer.ZkSync, payer.ZkWithdraw: - var err error - auditor, err = zksync.NewAuditor( - nodeAddress, - chainID) - if err != nil { - return nil, err - } case payer.ZkSyncEra: var err error auditor, err = zksyncera.NewAuditor(nodeAddress) diff --git a/pkg/receipts/buffer_test.go b/pkg/receipts/buffer_test.go index 6739b71..32b5b92 100644 --- a/pkg/receipts/buffer_test.go +++ b/pkg/receipts/buffer_test.go @@ -18,12 +18,12 @@ func TestBuffer(t *testing.T) { var b receipts.Buffer b.Emit(address1, decimal.NewFromInt(1), "hash1", payer.Eth) - b.Emit(address2, decimal.NewFromInt(2), "hash2", payer.ZkSync) + b.Emit(address2, decimal.NewFromInt(2), "hash2", payer.Eth) b.Emit(address3, decimal.NewFromInt(3), "hash3", payer.ZkSyncEra) receipts := b.Finalize() require.Equal(t, `wallet,amount,txhash,mechanism 0x0101010101010101010101010101010101010101,1,hash1,eth -0x0202020202020202020202020202020202020202,2,hash2,zksync +0x0202020202020202020202020202020202020202,2,hash2,eth 0x0303030303030303030303030303030303030303,3,hash3,zksync-era `, string(receipts)) } diff --git a/pkg/zksync/auditor.go b/pkg/zksync/auditor.go deleted file mode 100644 index 30a170f..0000000 --- a/pkg/zksync/auditor.go +++ /dev/null @@ -1,47 +0,0 @@ -package zksync - -import ( - "context" - - "storj.io/crypto-batch-payment/pkg/payer" - "storj.io/crypto-batch-payment/pkg/pipelinedb" -) - -type Auditor struct { - client *ZkClient -} - -func (a Auditor) CheckTransactionState(ctx context.Context, hash string) (pipelinedb.TxState, error) { - status, err := a.client.TxStatus(ctx, hash) - if err != nil { - return pipelinedb.TxFailed, err - } - return TxStateFromZkStatus(status), nil -} - -func (a Auditor) CheckConfirmedTransactionState(ctx context.Context, hash string) (pipelinedb.TxState, error) { - // TODO this is a double check based on current logic and later can be removed / simplified. - status, err := a.client.TxStatus(ctx, hash) - if err != nil { - return pipelinedb.TxFailed, err - } - return TxStateFromZkStatus(status), nil -} - -var ( - _ payer.Auditor = &Auditor{} -) - -func NewAuditor( - url string, - chainID int) (*Auditor, error) { - - client, err := NewZkClient(nil, url) - if err != nil { - return nil, err - } - client.ChainID = chainID - return &Auditor{ - client: &client, - }, nil -} diff --git a/pkg/zksync/doc.go b/pkg/zksync/doc.go deleted file mode 100644 index 52de230..0000000 --- a/pkg/zksync/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package zksync implements transfer operation on ZkSync network. -package zksync diff --git a/pkg/zksync/pack.go b/pkg/zksync/pack.go deleted file mode 100644 index 77a3bac..0000000 --- a/pkg/zksync/pack.go +++ /dev/null @@ -1,83 +0,0 @@ -package zksync - -import ( - "fmt" - "math/big" -) - -// packBigInt packs the value to expBits + mantissaBits. -func packBigInt(value *big.Int, expBits uint8, mantissaBits uint8) []byte { - maxMantissa := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(mantissaBits)), nil) - mantissa := value - base := big.NewInt(10) - exp := big.NewInt(0) - for mantissa.Cmp(maxMantissa) > 0 { - mantissa = new(big.Int).Div(mantissa, base) - exp = new(big.Int).Add(exp, big.NewInt(1)) - } - result := new(big.Int).Lsh(mantissa, uint(expBits)) - result = new(big.Int).Add(result, exp) - raw := result.Bytes() - size := (expBits + mantissaBits) / 8 - resultBytes := make([]byte, size) - for i := 0; i < int(size); i++ { - if len(raw) > i { - resultBytes[i] = raw[len(raw)-i-1] - } - } - return resultBytes -} - -// unpackBigInt unpacks the packed value. -func unpackBigInt(value []byte, expBits uint8) *big.Int { - left, right := splitByBits(value, expBits) - exp := new(big.Int).SetBytes(right) - mantissa := new(big.Int).SetBytes(left) - // mantissa * 10^exp - return new(big.Int).Mul(mantissa, new(big.Int).Exp(big.NewInt(10), exp, nil)) -} - -func closestPackableAmount(value *big.Int, expBits uint8, mantissaBits uint8) *big.Int { - unpacked := packBigInt(value, expBits, mantissaBits) - res := unpackBigInt(unpacked, expBits) - - // this should never even happen. The difference can be <9 on the last digit of a number with mantissaBits - // keeping it here for safety - percentageDiff := new(big.Int).Sub(new(big.Int).Div(value, res), big.NewInt(1)) - if percentageDiff.Cmp(big.NewInt(1)) > 0 { - panic(fmt.Sprintf("closestPackableAmount is failing, too big differences between old and new values (%s %s", value.String(), res.String())) - } - return res -} - -// splitByBits byte array by a bit number -// for example [abcdefgh pqrstuwx],5 should return with [000defgh], [pqr stuwxabc]. -func splitByBits(value []byte, splitPos uint8) ([]byte, []byte) { - split := splitPos - shift := uint8(0) - var left, right []byte - for _, x := range value { - if split >= 8 { - // still we are at the first part - right = append([]byte{x}, right...) - split -= 8 - } else if split > 0 { - // we should shift all the remaining value by this - shift = split - // drop the upper bytes - val := x << (8 - split) >> (8 - split) - right = append([]byte{val}, right...) - - split = 0 - - val = x >> shift - left = append(left, val) - } else { - if shift > 0 { - left[0] += +x << (8 - shift) - } - left = append([]byte{x >> shift}, left...) - } - } - return left, right -} diff --git a/pkg/zksync/pack_test.go b/pkg/zksync/pack_test.go deleted file mode 100644 index f38ed61..0000000 --- a/pkg/zksync/pack_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package zksync - -import ( - "encoding/hex" - "fmt" - "math/big" - "testing" - - "github.com/stretchr/testify/require" -) - -func Test_packBigInt(t *testing.T) { - require.Equal(t, "2000", hex.EncodeToString(packBigInt(big.NewInt(1), uint8(5), uint8(11)))) - require.Equal(t, "4001", hex.EncodeToString(packBigInt(big.NewInt(10), uint8(5), uint8(11)))) - require.Equal(t, "800c", hex.EncodeToString(packBigInt(big.NewInt(100), uint8(5), uint8(11)))) - require.Equal(t, "459a", hex.EncodeToString(packBigInt(big.NewInt(123456789), uint8(5), uint8(11)))) - require.Equal(t, "a34d", hex.EncodeToString(packBigInt(big.NewInt(621000), uint8(5), uint8(11)))) - require.Equal(t, "00ee0d1300", hex.EncodeToString(packBigInt(big.NewInt(9990000), uint8(5), uint8(35)))) -} - -func Test_unpack(t *testing.T) { - tests := []struct { - input []byte - split uint8 - expected *big.Int - }{ - { - input: []byte{0x00, 0xee, 0x0d, 0x13, 0x00}, - split: 5, - expected: big.NewInt(9990000), - }, - { - input: []byte{0x20, 00}, - split: 5, - expected: big.NewInt(1), - }, - } - - for _, testCase := range tests { - t.Run(fmt.Sprintf("Unpack %s", testCase.expected), func(t *testing.T) { - res := unpackBigInt(testCase.input, testCase.split) - require.Equal(t, testCase.expected, res) - }) - } -} - -func Test_packUnpack(t *testing.T) { - mBits := uint8(11) - expBits := uint8(5) - for i := 0; i < 20; i++ { - for _, k := range []int{1, 2, 16, 100, 1000, 10000} { - original := big.NewInt(int64(k * i)) - t.Run(fmt.Sprintf("Pack and unpack %s", original.String()), func(t *testing.T) { - packed := packBigInt(original, expBits, mBits) - unpacked := unpackBigInt(packed, expBits) - require.Equal(t, original, unpacked) - }) - } - } -} - -func Test_splitByBits(t *testing.T) { - tests := []struct { - name string - input []byte - split uint8 - left []byte - right []byte - }{ - { - name: "Split two bytes by 5", - input: []byte{0b001_10011, 0b11001100}, - split: 5, - left: []byte{0b00000110, 0b01100001}, - right: []byte{0b00010011}, - }, - { - name: "Split two bytes by 7", - input: []byte{0b0_0110011, 0b11001100}, - split: 7, - left: []byte{0b1, 0b10011000}, - right: []byte{0b0110011}, - }, - { - name: "Split two bytes by 8", - input: []byte{0b00110011, 0b00110011}, - split: 8, - left: []byte{0b00110011}, - right: []byte{0b00110011}, - }, - } - - for _, testCase := range tests { - t.Run(testCase.name, func(t *testing.T) { - left, right := splitByBits(testCase.input, testCase.split) - require.Equal(t, left, testCase.left) - require.Equal(t, right, testCase.right) - }) - } -} - -func Test_closestPackableAmount(t *testing.T) { - failedTxValue, ok := new(big.Int).SetString("36677776552", 10) - require.True(t, ok) - - tests := []struct { - input *big.Int - mantissa uint8 - exp uint8 - expected *big.Int - }{ - { - input: big.NewInt(256), - mantissa: 11, - exp: 5, - expected: big.NewInt(256), - }, - { - input: big.NewInt(1024), - mantissa: 11, - exp: 5, - expected: big.NewInt(1024), - }, - { - input: big.NewInt(102400), - mantissa: 11, - exp: 5, - expected: big.NewInt(102400), - }, - { - input: big.NewInt(4095), // 12 bits - mantissa: 11, - exp: 5, - expected: big.NewInt(4090), - }, - { - input: big.NewInt(4099), - mantissa: 11, - exp: 5, - expected: big.NewInt(4090), - }, - { - input: failedTxValue, - mantissa: 35, - exp: 5, - expected: big.NewInt(36677776550), - }, - } - - for _, testCase := range tests { - t.Run(fmt.Sprintf("Closest amount %s", testCase.input), func(t *testing.T) { - res := closestPackableAmount(testCase.input, testCase.exp, testCase.mantissa) - require.Equal(t, testCase.expected, res) - }) - } -} - -func Test_closestHigherPackableAmountRandom(t *testing.T) { - -} diff --git a/pkg/zksync/payer.go b/pkg/zksync/payer.go deleted file mode 100644 index 5d438f7..0000000 --- a/pkg/zksync/payer.go +++ /dev/null @@ -1,208 +0,0 @@ -package zksync - -import ( - "context" - "crypto/ecdsa" - "fmt" - "math/big" - "strings" - "time" - - "github.com/ethereum/go-ethereum/crypto" - - "github.com/ethereum/go-ethereum/common" - "github.com/shopspring/decimal" - "github.com/zeebo/errs/v2" - "go.uber.org/zap" - - "storj.io/crypto-batch-payment/pkg/payer" - "storj.io/crypto-batch-payment/pkg/pipelinedb" - "storj.io/crypto-batch-payment/pkg/storjtoken" -) - -type Payer struct { - client *ZkClient - token Token - withdraw bool // set to true to pay on l1 (from l2!) - maxFee *big.Int -} - -var ( - _ payer.Payer = &Payer{} -) - -func NewPayer( - ctx context.Context, - url string, - key *ecdsa.PrivateKey, - chainID int, - withdraw bool, - maxFee *big.Int) (*Payer, error) { - client, err := NewZkClient(key, url) - if err != nil { - return nil, err - } - client.ChainID = chainID - - token, err := client.GetToken(ctx, "STORJ") - if err != nil { - return nil, errs.Wrap(err) - } - - return &Payer{ - client: &client, - token: token, - withdraw: withdraw, - maxFee: maxFee, - }, nil -} - -func (z Payer) String() string { - return payer.ZkSync.String() -} - -func (z Payer) NextNonce(ctx context.Context) (uint64, error) { - return z.client.GetNonce(ctx) -} - -func (z Payer) CheckPreconditions(ctx context.Context) ([]string, error) { - return nil, nil -} - -func (z Payer) GetTokenBalance(ctx context.Context) (*big.Int, error) { - return z.client.GetBalance(ctx, "STORJ") -} - -func (z Payer) CreateRawTransaction(ctx context.Context, log *zap.Logger, payouts []*pipelinedb.Payout, nonce uint64, storjPrice decimal.Decimal) (tx payer.Transaction, from common.Address, err error) { - if len(payouts) > 1 { - return payer.Transaction{}, common.Address{}, errs.Errorf("multitransfer is not supported yet") - } - - address, err := z.client.Address() - if err != nil { - return payer.Transaction{}, common.Address{}, errs.Wrap(err) - } - - payout := payouts[0] - - var fee *big.Int - for { - fee, err = z.client.GetFee(ctx, z.TxTypeString(), payout.Payee.String(), "STORJ") - if err != nil { - return payer.Transaction{}, common.Address{}, errs.Wrap(err) - } - if z.maxFee == nil || z.maxFee.Cmp(fee) >= 0 { - break - } - log.Sugar().Infof("current fee (%s) greater than max fee (%s), sleeping", fee.String(), z.maxFee.String()) - time.Sleep(5 * time.Second) - } - - storjTokens := storjtoken.FromUSD(payout.USD, storjPrice, z.token.Decimals) - storjTokens = closestPackableAmount(storjTokens, amountExp, amountMantissa) - - txs, err := z.client.CreateTx(ctx, z.TxTypeString(), payout.Payee, storjTokens, fee, z.token, int(nonce)) - if err != nil { - return payer.Transaction{}, common.Address{}, errs.Wrap(err) - } - - hash, err := txs.Tx.Hash() - if err != nil { - return payer.Transaction{}, common.Address{}, errs.Wrap(err) - } - return payer.Transaction{ - Raw: txs, - Nonce: uint64(txs.Tx.Nonce), - Hash: hash, - }, address, nil - -} - -func (z Payer) SendTransaction(ctx context.Context, log *zap.Logger, t payer.Transaction) error { - switch tx := t.Raw.(type) { - case TxWithEthSignature: - txHash, err := z.client.SubmitTransaction(ctx, tx) - if err != nil { - return errs.Errorf("Transaction %s is failed: %+v", t.Hash, err) - } - if txHash != t.Hash { - return errs.Errorf("Transaction hash calculated wrongly %s!=%s", txHash, t.Hash) - } - return errs.Wrap(err) - default: - return errs.Errorf("ZkSyncPayer doesn't support transaction %v", t.Raw) - } -} - -func (z Payer) CheckNonceGroup(ctx context.Context, log *zap.Logger, nonceGroup *pipelinedb.NonceGroup, checkOnly bool) (pipelinedb.TxState, []*pipelinedb.TxStatus, error) { - if len(nonceGroup.Txs) != 1 { - return pipelinedb.TxFailed, nil, errs.Errorf("noncegroup should have only 1 transaction, not %d", len(nonceGroup.Txs)) - } - tx := nonceGroup.Txs[0] - hash := tx.Hash - - // zksync api doesn't accept TX in pure hex format - if !strings.HasPrefix(hash, "0x") && !strings.HasPrefix(hash, syncTxPrefix) { - hash = "0x" + hash - } - status, err := z.client.TxStatus(ctx, hash) - if err != nil { - return pipelinedb.TxFailed, nil, err - } - txStatus := TxStateFromZkStatus(status) - return txStatus, []*pipelinedb.TxStatus{ - { - Hash: tx.Hash, - State: txStatus, - Receipt: nil, - }, - }, nil -} - -func TxStateFromZkStatus(status TxStatus) pipelinedb.TxState { - if !status.Executed { - return pipelinedb.TxPending - } else if !status.Success { - return pipelinedb.TxFailed - } else if status.Executed { - return pipelinedb.TxConfirmed - } - return pipelinedb.TxPending -} - -func (z Payer) PrintEstimate(ctx context.Context, remaining int64) error { - if z.withdraw { - fmt.Println("Payment type................: L2->L1 (!)") - } else { - fmt.Println("Payment type................: L2->L2 (normal zksync)") - } - - // use generated address to get fee for cold addresses - rawKey, err := crypto.GenerateKey() - if err != nil { - return errs.Wrap(err) - } - address := crypto.PubkeyToAddress(rawKey.PublicKey).Hex() - - fee, err := z.client.GetFee(ctx, z.TxTypeString(), address, "STORJ") - if err != nil { - return errs.Wrap(err) - } - - fmt.Printf("Current fee / tx ...........: %s\n", storjtoken.Pretty(fee, z.token.Decimals)) - remainingFee := new(big.Int).Mul(fee, big.NewInt(remaining)) - fmt.Printf("Remaining tx fee ~ .........: %s\n", storjtoken.Pretty(remainingFee, z.token.Decimals)) - - return nil -} - -func (z Payer) GetTokenDecimals(ctx context.Context) (int32, error) { - return z.token.Decimals, nil -} - -func (z Payer) TxTypeString() string { - if z.withdraw { - return "Withdraw" - } - return "Transfer" -} diff --git a/pkg/zksync/zksync.go b/pkg/zksync/zksync.go deleted file mode 100644 index 5037591..0000000 --- a/pkg/zksync/zksync.go +++ /dev/null @@ -1,482 +0,0 @@ -package zksync - -import ( - "bytes" - "context" - "crypto/ecdsa" - "crypto/sha256" - "encoding/binary" - "encoding/hex" - "fmt" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rpc" - "github.com/shopspring/decimal" - "github.com/zeebo/errs" - zkscrypto "github.com/zksync-sdk/zksync-sdk-go" -) - -const feeMantissa = 11 -const amountMantissa = 35 -const amountExp = 5 -const feeExp = 5 -const syncTxPrefix = "sync-tx:" - -type ZkClient struct { - rpcURL string - httpURL string - - privateKey *ecdsa.PrivateKey - ChainID int - accountInfo *AccountInfo -} - -func NewZkClient(pk *ecdsa.PrivateKey, url string) (ZkClient, error) { - if url[len(url)-1] == '/' { - url = url[:len(url)-1] - } - return ZkClient{ - rpcURL: url + "/jsrpc", - httpURL: url + "/api/v1", - privateKey: pk, - ChainID: 1, - }, nil -} - -type Token struct { - Symbol string - Decimals int32 - ID int -} - -func (t Token) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf("%d", t.ID)), nil -} - -type Tx struct { - Type string `json:"type"` - AccountID int `json:"accountId"` - From common.Address `json:"from"` - To common.Address `json:"to"` - Token Token `json:"token"` - Amount *big.Int `json:"amount"` - Fee *big.Int `json:"fee"` - Nonce int `json:"nonce"` - Signature TxSignature `json:"signature"` -} - -type TxSignature struct { - PubKey string `json:"pubKey"` - Signature string `json:"signature"` -} -type Signature struct { - Type string `json:"type"` - Signature string `json:"signature"` -} -type TxWithEthSignature struct { - Tx Tx - Signature Signature -} - -const EtherSignMessage = "\x19Ethereum Signed Message:\n" -const ZkSyncMessage = "Access zkSync account.\n\nOnly sign this message for a trusted client!" - -// GetTypeID returns with the internal byte representation of the transaction type (or 0 if unsupported). -func (tx Tx) GetTypeID() byte { - switch tx.Type { - case "Withdraw": - // See: https://github.com/matter-labs/zksync/blob/b55ab5a7ec1fddd6c236980a54bc59babbe0076e/core/lib/types/src/tx/withdraw.rs#L62 - return byte(3) - case "Transfer": - // See: https://github.com/matter-labs/zksync/blob/b55ab5a7ec1fddd6c236980a54bc59babbe0076e/core/lib/types/src/tx/transfer.rs#L60 - return byte(5) - default: - return byte(0) - } - -} - -// Hash returns with the tx hash calculated from the struct values. -func (tx Tx) Hash() (string, error) { - encoded, err := tx.encodeForHash() - if err != nil { - return "", err - } - sum := sha256.Sum256(encoded) - return "0x" + hex.EncodeToString(sum[:]), nil -} - -func (tx Tx) encode() ([]byte, error) { - buf := new(bytes.Buffer) - _, err := buf.Write([]byte{tx.GetTypeID()}) - if err != nil { - return nil, err - } - - amountBytes := reverseBytes(packBigInt(tx.Amount, amountExp, amountMantissa)) - if tx.Type == "Withdraw" { - // L1->L2 withdraw should use full 16 bit for the amounts instead of packing - // see: https://github.com/matter-labs/zksync/blob/b55ab5a7ec1fddd6c236980a54bc59babbe0076e/sdk/zksync.js/src/utils.ts#L694 - amountBytes = make([]byte, 16) - tx.Amount.FillBytes(amountBytes) - } - - for _, value := range []interface{}{ - uint32(tx.AccountID), - tx.From.Bytes(), - tx.To.Bytes(), - uint16(tx.Token.ID), - amountBytes, - reverseBytes(packBigInt(tx.Fee, feeExp, feeMantissa)), - uint32(tx.Nonce), - } { - err = binary.Write(buf, binary.BigEndian, value) - if err != nil { - return nil, err - } - } - return buf.Bytes(), nil -} - -func (tx Tx) encodeForHash() ([]byte, error) { - buf := new(bytes.Buffer) - _, err := buf.Write([]byte{255 - tx.GetTypeID(), 1}) - if err != nil { - return nil, err - } - amountBytes := reverseBytes(packBigInt(tx.Amount, amountExp, amountMantissa)) - if tx.Type == "Withdraw" { - amountBytes = make([]byte, 16) - tx.Amount.FillBytes(amountBytes) - } - for _, value := range []interface{}{ - uint32(tx.AccountID), - tx.From.Bytes(), - tx.To.Bytes(), - uint32(tx.Token.ID), - amountBytes, - reverseBytes(packBigInt(tx.Fee, 5, 11)), - uint32(tx.Nonce), - } { - err = binary.Write(buf, binary.BigEndian, value) - if err != nil { - return nil, err - } - } - - // bytes represent time range added in - // https://github.com/matter-labs/zksync/commit/1c23f6e0 - m, err := hex.DecodeString("0000000000000000FFFFFFFFFFFFFFFF") - if err != nil { - return nil, err - } - return append(buf.Bytes(), m...), nil -} - -func (t *Token) Format(value *big.Int) string { - result := decimal.NewFromBigInt(value, -t.Decimals).String() - // note: 1 should be represented as 1.0 in the base string of eth signature - if !strings.Contains(result, ".") { - result += ".0" - } - return result -} - -func signHash(data []byte) common.Hash { - msg := fmt.Sprintf(EtherSignMessage+"%d%s", len(data), data) - return crypto.Keccak256Hash([]byte(msg)) -} - -func (c *ZkClient) privateKeySeed() ([]byte, error) { - dataToSign := ZkSyncMessage - if c.ChainID != 1 { - dataToSign += fmt.Sprintf("\nChain ID: %d.", c.ChainID) - } - signature, err := c.signMessage(dataToSign, true) - return signature, err -} - -func (c *ZkClient) signMessage(message string, pad bool) ([]byte, error) { - signHash := signHash([]byte(message)) - signature, err := crypto.Sign(signHash.Bytes(), c.privateKey) - if pad { - signature[len(signature)-1] = signature[len(signature)-1] + 27 - } - return signature, err -} - -func (c *ZkClient) zkPrivateKey() (*zkscrypto.PrivateKey, error) { - seed, err := c.privateKeySeed() - if err != nil { - return nil, err - } - return zkscrypto.NewPrivateKey(seed) -} - -func (c *ZkClient) ethereumSignature(tx Tx) ([]byte, error) { - humanReadableTxInfo := fmt.Sprintf( - "%s %s %s\n"+ - "To: %s\n"+ - "Nonce: %d\n"+ - "Fee: %s %s\n"+ - "Account Id: %d", - tx.Type, - tx.Token.Format(tx.Amount), - tx.Token.Symbol, - strings.ToLower(tx.To.String()), - tx.Nonce, - tx.Token.Format(tx.Fee), - tx.Token.Symbol, - tx.AccountID, - ) - return c.signMessage(humanReadableTxInfo, true) - -} - -func (c *ZkClient) Transfer(ctx context.Context, to common.Address, amount *big.Int, fee *big.Int, token Token) (string, error) { - err := c.fillAccountInfo(ctx) - if err != nil { - return "", err - } - nonce := int(c.accountInfo.Committed.Nonce) - txs, err := c.CreateTransferTx(ctx, to, amount, fee, token, nonce) - if err != nil { - return "", err - } - return c.SubmitTransaction(ctx, txs) -} - -func (c *ZkClient) SubmitTransaction(ctx context.Context, txs TxWithEthSignature) (string, error) { - client, err := rpc.DialContext(ctx, c.rpcURL) - if err != nil { - return "", err - } - defer client.Close() - - hash := "" - err = client.CallContext(ctx, &hash, "tx_submit", txs.Tx, txs.Signature) - if err != nil { - return "", err - } - - // our Canonical transaction format is pure 0xHEX - hash = strings.TrimPrefix(hash, syncTxPrefix) - if !strings.HasPrefix(hash, "0x") { - hash = "0x" + hash - } - return hash, err -} - -func (c *ZkClient) CreateTransferTx(ctx context.Context, to common.Address, amount *big.Int, fee *big.Int, token Token, nonce int) (TxWithEthSignature, error) { - return c.CreateTx(ctx, "Transfer", to, amount, fee, token, nonce) -} - -func (c *ZkClient) CreateTx(ctx context.Context, txType string, to common.Address, amount *big.Int, fee *big.Int, token Token, nonce int) (TxWithEthSignature, error) { - pk, err := c.zkPrivateKey() - if err != nil { - return TxWithEthSignature{}, err - } - err = c.fillAccountInfo(ctx) - if err != nil { - return TxWithEthSignature{}, err - } - - publicKey, err := pk.PublicKey() - if err != nil { - return TxWithEthSignature{}, err - } - from := crypto.PubkeyToAddress(c.privateKey.PublicKey) - - tx := Tx{ - AccountID: int(c.accountInfo.ID), - Nonce: nonce, - Type: txType, - From: from, - To: to, - Amount: amount, - Fee: fee, - Token: token, - } - zkSignature, err := c.zkSignature(tx) - if err != nil { - return TxWithEthSignature{}, err - } - tx.Signature = TxSignature{ - Signature: hex.EncodeToString(zkSignature), - PubKey: publicKey.HexString(), - } - - ethSignature, err := c.ethereumSignature(tx) - if err != nil { - return TxWithEthSignature{}, err - } - ethereumSignature := Signature{ - Type: "EthereumSignature", - Signature: "0x" + hex.EncodeToString(ethSignature), - } - return TxWithEthSignature{ - Signature: ethereumSignature, - Tx: tx, - }, nil -} - -func (c *ZkClient) zkSignature(tx Tx) ([]byte, error) { - - pk, err := c.zkPrivateKey() - if err != nil { - return nil, err - } - encoded, err := tx.encode() - if err != nil { - return nil, err - } - signature, err := pk.Sign(encoded) - if err != nil { - return nil, err - } - result, err := hex.DecodeString(signature.HexString()) - if err != nil { - return nil, err - } - return result, nil -} - -type AccountInfo struct { - ID int64 - Address string - Committed AccountState - Verified AccountState -} -type AccountState struct { - Balances map[string]string - Nonce uint64 -} - -func (c *ZkClient) fillAccountInfo(ctx context.Context) error { - if c.accountInfo != nil { - return nil - } - return c.refreshAccountInfo(ctx) - -} - -func (c *ZkClient) refreshAccountInfo(ctx context.Context) error { - client, err := rpc.DialContext(ctx, c.rpcURL) - if err != nil { - return err - } - defer client.Close() - - addr := crypto.PubkeyToAddress(c.privateKey.PublicKey) - result := AccountInfo{} - err = client.CallContext(ctx, &result, "account_info", addr) - if err != nil { - return err - } - c.accountInfo = &result - return nil -} - -func (c *ZkClient) GetBalance(ctx context.Context, instrument string) (*big.Int, error) { - err := c.fillAccountInfo(ctx) - if err != nil { - return nil, err - } - balanceString := c.accountInfo.Committed.Balances[instrument] - balance, ok := new(big.Int).SetString(balanceString, 10) - if !ok { - return big.NewInt(0), errs.New("Invalid balance string") - } - return balance, nil -} - -func (c *ZkClient) GetFee(ctx context.Context, txType string, address string, instrument string) (*big.Int, error) { - client, err := rpc.DialContext(ctx, c.rpcURL) - if err != nil { - return big.NewInt(0), err - } - defer client.Close() - - result := map[string]interface{}{} - err = client.CallContext(ctx, &result, "get_tx_fee", txType, address, instrument) - if err != nil { - return big.NewInt(0), err - } - fee, _ := new(big.Int).SetString(result["totalFee"].(string), 10) - return fee, nil -} - -func (c *ZkClient) GetNonce(ctx context.Context) (uint64, error) { - err := c.refreshAccountInfo(ctx) - if err != nil { - return 0, err - } - nonce := c.accountInfo.Committed.Nonce - return nonce, nil -} - -func (c *ZkClient) Address() (common.Address, error) { - pk, err := c.zkPrivateKey() - if err != nil { - return common.Address{}, err - } - publicKey, err := pk.PublicKey() - if err != nil { - return common.Address{}, err - } - from := common.HexToAddress(publicKey.HexString()) - return from, nil -} - -type TxStatus struct { - Executed bool - Success bool - Block BlockStatus -} - -type BlockStatus struct { - Committed bool - Verified bool - BlockNumber int -} - -func (c *ZkClient) TxStatus(ctx context.Context, txHash string) (TxStatus, error) { - client, err := rpc.DialContext(ctx, c.rpcURL) - if err != nil { - return TxStatus{}, err - } - defer client.Close() - result := TxStatus{} - err = client.CallContext(ctx, &result, "tx_info", txHash) - return result, err -} - -func (c *ZkClient) GetToken(ctx context.Context, symbol string) (Token, error) { - client, err := rpc.DialContext(ctx, c.rpcURL) - if err != nil { - return Token{}, err - } - defer client.Close() - tokens := make(map[string]Token) - err = client.CallContext(ctx, &tokens, "tokens") - if err != nil { - return Token{}, err - } - if token, found := tokens[symbol]; found { - return token, nil - } else { - return Token{}, errs.New("Couldn't find token %symbol", symbol) - } - -} - -func reverseBytes(bigInt []byte) []byte { - reversed := make([]byte, len(bigInt)) - for i := 0; i < len(bigInt); i++ { - reversed[i] = bigInt[len(bigInt)-1-i] - } - return reversed -} diff --git a/pkg/zksync/zksync_test.go b/pkg/zksync/zksync_test.go deleted file mode 100644 index 9c5f4e4..0000000 --- a/pkg/zksync/zksync_test.go +++ /dev/null @@ -1,339 +0,0 @@ -package zksync - -import ( - "context" - "crypto/ecdsa" - "encoding/hex" - "fmt" - "math/big" - "os" - "strings" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/require" -) - -func Test_Nonce(t *testing.T) { - t.Skip("This test doesn't work any more, as account doesn't have history on goerli test chain") - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/jsrpc") - client.ChainID = 4 - require.NoError(t, err) - ctx := context.Background() - nonce, err := client.GetNonce(ctx) - require.NoError(t, err) - require.Greater(t, nonce, uint64(0)) -} - -func Test_Fee(t *testing.T) { - t.Skip("This test doesn't work any more as STORJ token can't be used to pay the fee") - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/jsrpc") - client.ChainID = 4 - require.NoError(t, err) - ctx := context.Background() - fee, err := client.GetFee(ctx, "Transfer", "0xbd9294F0232a84Da9602B9B13f1Fca173b7A7CA8", "STORJ") - require.NoError(t, err) - require.Greater(t, fee.Uint64(), uint64(10)) -} - -func Test_Transfer(t *testing.T) { - if os.Getenv("TEST_WRITE") == "" { - t.Skip("Skipping test which requires on-chain tx") - } - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/jsrpc") - client.ChainID = 4 - require.NoError(t, err) - ctx := context.Background() - receipt, err := client.Transfer(ctx, - common.HexToAddress("0xcEE63e28E874eB80AF9eBCeC7b96F7cEbE3e92D8"), - big.NewInt(10), - big.NewInt(704000), - Token{ - Decimals: 8, - Symbol: "STORJ", - ID: 11, - }, - ) - require.NoError(t, err) - fmt.Println(receipt) -} - -func Test_TransferTwoPhases(t *testing.T) { - if os.Getenv("TEST_WRITE") == "" { - t.Skip("Skipping test which requires on-chain tx") - } - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/jsrpc") - client.ChainID = 4 - require.NoError(t, err) - ctx := context.Background() - txs, err := client.CreateTransferTx(ctx, - common.HexToAddress("0xcEE63e28E874eB80AF9eBCeC7b96F7cEbE3e92D8"), - big.NewInt(10), - big.NewInt(704000), - Token{ - Decimals: 8, - Symbol: "STORJ", - ID: 11, - }, 10) - require.NoError(t, err) - hash, err := txs.Tx.Hash() - require.NoError(t, err) - require.Equal(t, hash, "50986a7189d6babbe3c3ca3ed61dce81611ad177f2d53e86d37e5993872b94f9") - - res, err := client.SubmitTransaction(ctx, txs) - require.NoError(t, err) - require.Equal(t, hash, res) -} - -func Test_WithdrawTwoPhases(t *testing.T) { - if os.Getenv("TEST_WRITE") == "" { - t.Skip("Skipping test which requires on-chain tx") - } - pk, err := crypto.HexToECDSA(os.Getenv("TEST_PRIVATE_KEY")) - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/jsrpc") - client.ChainID = 4 - require.NoError(t, err) - ctx := context.Background() - - target := "0xB766AE0dd39F26bC5E8f60fC1C95566eCFE3851f" - - nonce, err := client.GetNonce(ctx) - require.NoError(t, err) - - token, err := client.GetToken(ctx, "STORJ") - require.NoError(t, err) - - fee, err := client.GetFee(ctx, "Withdraw", crypto.PubkeyToAddress(pk.PublicKey).Hex(), "STORJ") - require.NoError(t, err) - - txs, err := client.CreateTx(ctx, - "Withdraw", - common.HexToAddress(target), - big.NewInt(6270), - fee, - token, - int(nonce)) - - require.NoError(t, err) - - hash, err := txs.Tx.Hash() - require.NoError(t, err) - - res, err := client.SubmitTransaction(ctx, txs) - require.NoError(t, err) - require.Equal(t, hash, res) -} - -func Test_PrivateKeySeed(t *testing.T) { - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/jsrpc") - require.NoError(t, err) - client.ChainID = 4 - - seed, err := client.privateKeySeed() - require.NoError(t, err) - require.Equal(t, "286267a4e6b69668c3e5423f0098cb719aa844ae71ee1ad85b2562c37994bbb9539008e1b729af522bc4e11d0e57e06bee9dbcdff50f8d4083a61cc21e35065e1c", common.Bytes2Hex(seed)) -} - -func Test_PrivateKey(t *testing.T) { - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/") - require.NoError(t, err) - client.ChainID = 4 - - zkpk, err := client.zkPrivateKey() - require.NoError(t, err) - zkpub, err := zkpk.PublicKey() - require.NoError(t, err) - - require.Equal(t, "931fcb506443c23cd4b23e49ce6a20a72e4826110bd3190a1ac02fdc45b7982d", zkpub.HexString()) -} - -func Test_Priv(t *testing.T) { - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/") - require.NoError(t, err) - client.ChainID = 4 - - seed, err := client.privateKeySeed() - require.NoError(t, err) - require.Equal(t, "286267a4e6b69668c3e5423f0098cb719aa844ae71ee1ad85b2562c37994bbb9539008e1b729af522bc4e11d0e57e06bee9dbcdff50f8d4083a61cc21e35065e1c", common.Bytes2Hex(seed)) -} - -func Test_token(t *testing.T) { - storj := Token{ - Decimals: 8, - Symbol: "STORJ", - ID: 11, - } - - require.Equal(t, "0.12345678", storj.Format(big.NewInt(12345678))) -} - -func Test_GetToken(t *testing.T) { - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - checkToken(t, pk, "https://goerli-api.zksync.io/", "STORJ", 11, 8) - checkToken(t, pk, "https://api.zksync.io/", "STORJ", 24, 8) -} - -func checkToken(t *testing.T, pk *ecdsa.PrivateKey, api string, symbol string, id int, decimals int32) { - t.Skip("Token doesn't exist on the new chain") - client, err := NewZkClient(pk, api) - require.NoError(t, err) - client.ChainID = 4 - - ctx := context.Background() - token, err := client.GetToken(ctx, symbol) - require.NoError(t, err) - require.Equal(t, symbol, token.Symbol) - require.Equal(t, id, token.ID) - require.Equal(t, decimals, token.Decimals) -} - -func Test_ethereumSignature(t *testing.T) { - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/") - require.NoError(t, err) - client.ChainID = 4 - - tx := Tx{ - Type: "Transfer", - AccountID: 236843, - From: common.HexToAddress("0xA72fD7554c9aC2c89D241f4A4Fd0351A4976c835"), - To: common.HexToAddress("0xcEE63e28E874eB80AF9eBCeC7b96F7cEbE3e92D8"), - Token: Token{ - Symbol: "STORJ", - ID: 11, - Decimals: 8, - }, - Amount: big.NewInt(2300000000), - Fee: big.NewInt(621000), - Nonce: 2, - } - signature, err := client.ethereumSignature(tx) - require.NoError(t, err) - require.Equal(t, "55412b1906b455ab43baa47ebdae4ea2b3109d0ac8b19ef885441b155e0fe714670e79facd04468c79ed5049ee5b25dda3fba9077998fcb190cf4942afa560851c", - common.Bytes2Hex(signature)) -} - -func Test_zkSignature(t *testing.T) { - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/") - require.NoError(t, err) - client.ChainID = 4 - - tx := Tx{ - Type: "Transfer", - AccountID: 236843, - From: common.HexToAddress("0xA72fD7554c9aC2c89D241f4A4Fd0351A4976c835"), - To: common.HexToAddress("0xcEE63e28E874eB80AF9eBCeC7b96F7cEbE3e92D8"), - Token: Token{ - Symbol: "STORJ", - ID: 11, - Decimals: 8, - }, - Amount: big.NewInt(9990000), - Fee: big.NewInt(704000), - Nonce: 5, - } - signature, err := client.zkSignature(tx) - require.NoError(t, err) - require.Equal(t, "ed35d342131e73b644456866188098b6696d3ac40e3da04d78e9348ad74d2494efb7e13e957b434183803e97da00a2d14d45c3dbceae0dcd5380d0383fe3b405", common.Bytes2Hex(signature)) -} - -func Test_txHashTransfer(t *testing.T) { - tx := Tx{ - Type: "Transfer", - AccountID: 945169, - From: common.HexToAddress("0x303edcd8dbe1607fe512d45cc15d3e41fa4db44b"), - To: common.HexToAddress("0xf993b7a9e7a80d3d4f54c8f996fb247d416313c0"), - Amount: big.NewInt(156148485580), - Fee: big.NewInt(5170000), - Nonce: 23523, - Token: Token{ - Decimals: 8, - Symbol: "STORJ", - ID: 24, - }, - } - base, err := tx.encodeForHash() - require.NoError(t, err) - require.Equal(t, "FA01000E6C11303EDCD8DBE1607FE512D45CC15D3E41FA4DB44BF993B7A9E7A80D3D4F54C8F996FB247D416313C0000000187456F5C5C140A400005BE30000000000000000FFFFFFFFFFFFFFFF", strings.ToUpper(hex.EncodeToString(base))) - hash, err := tx.Hash() - require.NoError(t, err) - require.Equal(t, "0xf4df3bd1abe68e16b534417f60a7451544e56e2820e1a0a0d06b1bdcfab56b87", hash) -} - -func Test_txHashWithdraw(t *testing.T) { - t.Skip("TODO, it's failing. Sg. has been changed.") - tx := Tx{ - Type: "Withdraw", - AccountID: 362737, - From: common.HexToAddress("0x712ce0cbee9423e414493542ffebf418c16c1c96"), - To: common.HexToAddress("0xb766ae0dd39f26bc5e8f60fc1c95566ecfe3851f"), - Amount: big.NewInt(6270), - Fee: big.NewInt(1938000), - Nonce: 15, - Token: Token{ - Decimals: 8, - Symbol: "STORJ", - ID: 11, - }, - } - hash, err := tx.Hash() - require.NoError(t, err) - require.Equal(t, "0xab4555f8111f18a4a8c449094218ab8853e3464bf89500baed7739d6b8f852bd", hash) -} - -func Test_TxStatus(t *testing.T) { - t.Skip("Doesn't work, hard coded transaction is missing from the new test chain") - pk, err := crypto.HexToECDSA("add336fb48ab11ee615f67295e80a692e6ea03367f7585ffc40651e65059adf2") - require.NoError(t, err) - - client, err := NewZkClient(pk, "https://goerli-api.zksync.io/") - client.ChainID = 4 - require.NoError(t, err) - ctx := context.Background() - status, err := client.TxStatus(ctx, "0xb06bbafb874b1c8e8f62d1b635ba5fded83c147869566f10e0d855127a087caa") - require.NoError(t, err) - require.True(t, status.Executed) - require.True(t, status.Success) - require.Equal(t, 67181, status.Block.BlockNumber) -} - -func Test_TokenFormat(t *testing.T) { - token := Token{ - Symbol: "STORJ", - Decimals: 8, - ID: 11, - } - require.Equal(t, "1.0", token.Format(big.NewInt(100000000))) - require.Equal(t, "0.83", token.Format(big.NewInt(83000000))) -}