diff --git a/precompiles/bank/method_deposit.go b/precompiles/bank/method_deposit.go index b3ae3e0506..b262438b87 100644 --- a/precompiles/bank/method_deposit.go +++ b/precompiles/bank/method_deposit.go @@ -142,7 +142,7 @@ func unpackDepositArgs(args []interface{}) (zrc20Addr common.Address, amount *bi } amount, ok = args[1].(*big.Int) - if !ok || amount.Sign() <= 0 || amount == nil || amount == new(big.Int) { + if !ok || amount == nil || amount.Sign() <= 0 { return common.Address{}, nil, &ptypes.ErrInvalidAmount{ Got: amount.String(), } diff --git a/precompiles/bank/method_withdraw.go b/precompiles/bank/method_withdraw.go index f7848c5e43..32bc570cd3 100644 --- a/precompiles/bank/method_withdraw.go +++ b/precompiles/bank/method_withdraw.go @@ -86,9 +86,9 @@ func (c *Contract) withdraw( // Check if fungible address has enough ZRC20 balance. if err := c.fungibleKeeper.CheckFungibleZRC20Balance(ctx, c.zrc20ABI, zrc20Addr, amount); err != nil { - return nil, &ptypes.ErrUnexpected{ - When: "balanceOf", - Got: err.Error(), + return nil, &ptypes.ErrInsufficientBalance{ + Requested: amount.String(), + Got: err.Error(), } } @@ -134,7 +134,7 @@ func unpackWithdrawArgs(args []interface{}) (zrc20Addr common.Address, amount *b } amount, ok = args[1].(*big.Int) - if !ok || amount.Sign() <= 0 || amount == nil || amount == new(big.Int) { + if !ok || amount == nil || amount.Sign() <= 0 { return common.Address{}, nil, &ptypes.ErrInvalidAmount{ Got: amount.String(), } diff --git a/x/fungible/keeper/zrc20_check_allowance.go b/x/fungible/keeper/zrc20_check_allowance.go deleted file mode 100644 index 538f985c47..0000000000 --- a/x/fungible/keeper/zrc20_check_allowance.go +++ /dev/null @@ -1,72 +0,0 @@ -package keeper - -import ( - "fmt" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - - fungibletypes "github.com/zeta-chain/node/x/fungible/types" -) - -const allowance = "allowance" - -// CheckFungibleZRC20Allowance checks if the allowance of ZRC20 tokens, -// is equal or greater than the provided amount. -func (k Keeper) CheckFungibleZRC20Allowance( - ctx sdk.Context, - zrc20ABI *abi.ABI, - from, zrc20Address common.Address, - amount *big.Int, -) error { - if amount.Sign() <= 0 { - return fmt.Errorf("amount must be positive, got: %s", amount.String()) - } - - if from == zeroAddress { - return fmt.Errorf("from address cannot be zero") - } - - if zrc20Address == zeroAddress { - return fmt.Errorf("zrc20 address cannot be zero") - } - - args := []interface{}{from, fungibletypes.ModuleAddressZEVM} - res, err := k.CallEVM( - ctx, - *zrc20ABI, - fungibletypes.ModuleAddressZEVM, - zrc20Address, - big.NewInt(0), - nil, - true, - true, - allowance, - args..., - ) - if err != nil { - return err - } - - if res.VmError != "" { - return fmt.Errorf("%s", res.VmError) - } - - ret, err := zrc20ABI.Methods[allowance].Outputs.Unpack(res.Ret) - if err != nil { - return err - } - - allowance, ok := ret[0].(*big.Int) - if !ok { - return fmt.Errorf("ZRC20 allowance returned an unexpected type") - } - - if allowance.Cmp(amount) < 0 || allowance.Cmp(big.NewInt(0)) <= 0 { - return fmt.Errorf("invalid allowance, got: %s", allowance.String()) - } - - return nil -} diff --git a/x/fungible/keeper/zrc20_check_balance.go b/x/fungible/keeper/zrc20_check_balance.go deleted file mode 100644 index 34e393d6b9..0000000000 --- a/x/fungible/keeper/zrc20_check_balance.go +++ /dev/null @@ -1,67 +0,0 @@ -package keeper - -import ( - "fmt" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - - fungibletypes "github.com/zeta-chain/node/x/fungible/types" -) - -const balanceOf = "balanceOf" - -// CheckFungibleZRC20Balance checks if the balance of ZRC20 tokens, -// is equal or greater than the provided amount. -func (k Keeper) CheckFungibleZRC20Balance( - ctx sdk.Context, - zrc20ABI *abi.ABI, - zrc20Address common.Address, - amount *big.Int, -) error { - if amount.Sign() <= 0 { - return fmt.Errorf("amount must be positive, got: %s", amount.String()) - } - - if zrc20Address == zeroAddress { - return fmt.Errorf("zrc20 address cannot be zero") - } - - res, err := k.CallEVM( - ctx, - *zrc20ABI, - fungibletypes.ModuleAddressZEVM, - zrc20Address, - big.NewInt(0), - nil, - true, - true, - balanceOf, - fungibletypes.ModuleAddressZEVM, - ) - if err != nil { - return err - } - - if res.VmError != "" { - return fmt.Errorf("%s", res.VmError) - } - - ret, err := zrc20ABI.Methods[balanceOf].Outputs.Unpack(res.Ret) - if err != nil { - return err - } - - balance, ok := ret[0].(*big.Int) - if !ok { - return fmt.Errorf("ZRC20 balanceOf returned an unexpected type") - } - - if balance.Cmp(amount) == -1 { - return fmt.Errorf("invalid balance, got: %s", balance.String()) - } - - return nil -} diff --git a/x/fungible/keeper/zrc20_check_token_validity.go b/x/fungible/keeper/zrc20_check_token_validity.go deleted file mode 100644 index bd4bf21c5b..0000000000 --- a/x/fungible/keeper/zrc20_check_token_validity.go +++ /dev/null @@ -1,26 +0,0 @@ -package keeper - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" -) - -// IsValidZRC20 returns an error whenever a ZRC20 is not whitelisted or paused. -func (k Keeper) IsValidZRC20(ctx sdk.Context, zrc20Address common.Address) error { - if zrc20Address == zeroAddress { - return fmt.Errorf("zrc20 address cannot be zero") - } - - t, found := k.GetForeignCoins(ctx, zrc20Address.String()) - if !found { - return fmt.Errorf("ZRC20 is not whitelisted, address: %s", zrc20Address.String()) - } - - if t.Paused { - return fmt.Errorf("ZRC20 is paused, address: %s", zrc20Address.String()) - } - - return nil -} diff --git a/x/fungible/keeper/zrc20_cosmos_coins_mapping.go b/x/fungible/keeper/zrc20_cosmos_coins_mapping.go new file mode 100644 index 0000000000..4d5e86ae21 --- /dev/null +++ b/x/fungible/keeper/zrc20_cosmos_coins_mapping.go @@ -0,0 +1,321 @@ +package keeper + +import ( + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/zeta-chain/node/pkg/crypto" + fungibletypes "github.com/zeta-chain/node/x/fungible/types" +) + +const ( + transferFrom = "transferFrom" + transfer = "transfer" + balanceOf = "balanceOf" + allowance = "allowance" +) + +var ( + ErrZRC20ZeroAddress = fmt.Errorf("ZRC20 address cannot be zero") + ErrZRC20NotWhiteListed = fmt.Errorf("ZRC20 is not whitelisted") + ErrZRC20Paused = fmt.Errorf("ZRC20 is paused") + ErrZRC20NilABI = fmt.Errorf("ZRC20 ABI is nil") + ErrZeroAddress = fmt.Errorf("address cannot be zero") + ErrInvalidAmount = fmt.Errorf("amount must be positive") +) + +// LockZRC20 locks ZRC20 tokens in the bank contract. +// The caller must have approved the bank contract to spend the amount of ZRC20 tokens. +func (k Keeper) LockZRC20( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, from common.Address, + amount *big.Int, +) error { + if zrc20ABI == nil { + return ErrZRC20NilABI + } + + if amount.Sign() <= 0 || amount == nil { + return ErrInvalidAmount + } + + if crypto.IsEmptyAddress(from) { + return ErrZeroAddress + } + + if crypto.IsEmptyAddress(zrc20Address) { + return ErrZRC20ZeroAddress + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return err + } + + if err := k.CheckFungibleZRC20Allowance(ctx, zrc20ABI, from, zrc20Address, amount); err != nil { + return err + } + + args := []interface{}{from, fungibletypes.ModuleAddressZEVM, amount} + res, err := k.CallEVM( + ctx, + *zrc20ABI, + fungibletypes.ModuleAddressZEVM, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + transferFrom, + args..., + ) + if err != nil { + return err + } + + if res.VmError != "" { + return fmt.Errorf("EVM execution error in LockZRC20: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[transferFrom].Outputs.Unpack(res.Ret) + if err != nil { + return err + } + + if len(ret) == 0 { + return fmt.Errorf("no data returned from 'transferFrom' method") + } + + transferred, ok := ret[0].(bool) + if !ok { + return fmt.Errorf("transferFrom returned an unexpected value") + } + + if !transferred { + return fmt.Errorf("transferFrom not successful") + } + + return nil +} + +// UnlockZRC20 unlocks ZRC20 tokens and sends them to the "to" address. +func (k Keeper) UnlockZRC20( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, to common.Address, + amount *big.Int, +) error { + if zrc20ABI == nil { + return ErrZRC20NilABI + } + + if amount.Sign() <= 0 || amount == nil { + return ErrInvalidAmount + } + + if crypto.IsEmptyAddress(to) { + return ErrZeroAddress + } + + if crypto.IsEmptyAddress(zrc20Address) { + return ErrZRC20ZeroAddress + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return err + } + + if err := k.CheckFungibleZRC20Balance(ctx, zrc20ABI, zrc20Address, amount); err != nil { + return err + } + + args := []interface{}{to, amount} + res, err := k.CallEVM( + ctx, + *zrc20ABI, + fungibletypes.ModuleAddressZEVM, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + transfer, + args..., + ) + if err != nil { + return err + } + + if res.VmError != "" { + return fmt.Errorf("EVM execution error in UnlockZRC20: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[transfer].Outputs.Unpack(res.Ret) + if err != nil { + return err + } + + if len(ret) == 0 { + return fmt.Errorf("no data returned from 'transfer' method") + } + + transferred, ok := ret[0].(bool) + if !ok { + return fmt.Errorf("transfer returned an unexpected value") + } + + if !transferred { + return fmt.Errorf("transfer not successful") + } + + return nil +} + +// CheckFungibleZRC20Allowance checks if the allowance of ZRC20 tokens, +// is equal or greater than the provided amount. +func (k Keeper) CheckFungibleZRC20Allowance( + ctx sdk.Context, + zrc20ABI *abi.ABI, + from, zrc20Address common.Address, + amount *big.Int, +) error { + if zrc20ABI == nil { + return ErrZRC20NilABI + } + + if amount.Sign() <= 0 || amount == nil { + return ErrInvalidAmount + } + + if crypto.IsEmptyAddress(from) { + return ErrZeroAddress + } + + if crypto.IsEmptyAddress(zrc20Address) { + return ErrZRC20ZeroAddress + } + + args := []interface{}{from, fungibletypes.ModuleAddressZEVM} + res, err := k.CallEVM( + ctx, + *zrc20ABI, + fungibletypes.ModuleAddressZEVM, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + allowance, + args..., + ) + if err != nil { + return err + } + + if res.VmError != "" { + return fmt.Errorf("EVM execution error calling allowance: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[allowance].Outputs.Unpack(res.Ret) + if err != nil { + return err + } + + if len(ret) == 0 { + return fmt.Errorf("no data returned from 'allowance' method") + } + + allowanceValue, ok := ret[0].(*big.Int) + if !ok { + return fmt.Errorf("ZRC20 allowance returned an unexpected type") + } + + if allowanceValue.Cmp(amount) < 0 || allowanceValue.Cmp(big.NewInt(0)) <= 0 { + return fmt.Errorf("invalid allowance, got: %s", allowanceValue.String()) + } + + return nil +} + +// CheckFungibleZRC20Balance checks if the balance of ZRC20 tokens, +// is equal or greater than the provided amount. +func (k Keeper) CheckFungibleZRC20Balance( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address common.Address, + amount *big.Int, +) error { + if zrc20ABI == nil { + return ErrZRC20NilABI + } + + if amount.Sign() <= 0 || amount == nil { + return ErrInvalidAmount + } + + if crypto.IsEmptyAddress(zrc20Address) { + return ErrZRC20ZeroAddress + } + + res, err := k.CallEVM( + ctx, + *zrc20ABI, + fungibletypes.ModuleAddressZEVM, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + balanceOf, + fungibletypes.ModuleAddressZEVM, + ) + if err != nil { + return err + } + + if res.VmError != "" { + return fmt.Errorf("EVM execution error calling balanceOf: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[balanceOf].Outputs.Unpack(res.Ret) + if err != nil { + return err + } + + if len(ret) == 0 { + return fmt.Errorf("no data returned from 'balanceOf' method") + } + + balance, ok := ret[0].(*big.Int) + if !ok { + return fmt.Errorf("ZRC20 balanceOf returned an unexpected type") + } + + if balance.Cmp(amount) == -1 { + return fmt.Errorf("invalid balance, got: %s", balance.String()) + } + + return nil +} + +// IsValidZRC20 returns an error whenever a ZRC20 is not whitelisted or paused. +func (k Keeper) IsValidZRC20(ctx sdk.Context, zrc20Address common.Address) error { + if crypto.IsEmptyAddress(zrc20Address) { + return ErrZRC20ZeroAddress + } + + t, found := k.GetForeignCoins(ctx, zrc20Address.String()) + if !found { + return ErrZRC20NotWhiteListed + } + + if t.Paused { + return ErrZRC20Paused + } + + return nil +} diff --git a/x/fungible/keeper/zrc20_lock_token.go b/x/fungible/keeper/zrc20_lock_token.go deleted file mode 100644 index 1f96e20e55..0000000000 --- a/x/fungible/keeper/zrc20_lock_token.go +++ /dev/null @@ -1,82 +0,0 @@ -package keeper - -import ( - "fmt" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - - fungibletypes "github.com/zeta-chain/node/x/fungible/types" -) - -const transferFrom = "transferFrom" - -var zeroAddress common.Address = common.HexToAddress("0x0000000000000000000000000000000000000000") - -// LockZRC20 locks ZRC20 tokens in the bank contract. -// The caller must have approved the bank contract to spend the amount of ZRC20 tokens. -func (k Keeper) LockZRC20( - ctx sdk.Context, - zrc20ABI *abi.ABI, - zrc20Address, from common.Address, - amount *big.Int, -) error { - if amount.Sign() <= 0 { - return fmt.Errorf("amount must be positive, got: %s", amount.String()) - } - - if from == zeroAddress { - return fmt.Errorf("from address cannot be zero") - } - - if zrc20Address == zeroAddress { - return fmt.Errorf("zrc20 address cannot be zero") - } - - if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { - return err - } - - if err := k.CheckFungibleZRC20Allowance(ctx, zrc20ABI, from, zrc20Address, amount); err != nil { - return err - } - - args := []interface{}{from, fungibletypes.ModuleAddressZEVM, amount} - res, err := k.CallEVM( - ctx, - *zrc20ABI, - fungibletypes.ModuleAddressZEVM, - zrc20Address, - big.NewInt(0), - nil, - true, - true, - transferFrom, - args..., - ) - if err != nil { - return err - } - - if res.VmError != "" { - return fmt.Errorf("%s", res.VmError) - } - - ret, err := zrc20ABI.Methods[transferFrom].Outputs.Unpack(res.Ret) - if err != nil { - return err - } - - transferred, ok := ret[0].(bool) - if !ok { - return fmt.Errorf("transferFrom returned an unexpected value") - } - - if !transferred { - return fmt.Errorf("transferFrom not successful") - } - - return nil -} diff --git a/x/fungible/keeper/zrc20_unlock_token.go b/x/fungible/keeper/zrc20_unlock_token.go deleted file mode 100644 index 26f917fe82..0000000000 --- a/x/fungible/keeper/zrc20_unlock_token.go +++ /dev/null @@ -1,79 +0,0 @@ -package keeper - -import ( - "fmt" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - - fungibletypes "github.com/zeta-chain/node/x/fungible/types" -) - -const transfer = "transfer" - -// UnlockZRC20 unlocks ZRC20 tokens and sends them to the "to" address. -func (k Keeper) UnlockZRC20( - ctx sdk.Context, - zrc20ABI *abi.ABI, - zrc20Address, to common.Address, - amount *big.Int, -) error { - if amount.Sign() <= 0 { - return fmt.Errorf("amount must be positive, got: %s", amount.String()) - } - - if to == zeroAddress { - return fmt.Errorf("from address cannot be zero") - } - - if zrc20Address == zeroAddress { - return fmt.Errorf("zrc20 address cannot be zero") - } - - if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { - return err - } - - if err := k.CheckFungibleZRC20Balance(ctx, zrc20ABI, zrc20Address, amount); err != nil { - return err - } - - args := []interface{}{to, amount} - res, err := k.CallEVM( - ctx, - *zrc20ABI, - fungibletypes.ModuleAddressZEVM, - zrc20Address, - big.NewInt(0), - nil, - true, - true, - transfer, - args..., - ) - if err != nil { - return err - } - - if res.VmError != "" { - return fmt.Errorf("%s", res.VmError) - } - - ret, err := zrc20ABI.Methods[transfer].Outputs.Unpack(res.Ret) - if err != nil { - return err - } - - transferred, ok := ret[0].(bool) - if !ok { - return fmt.Errorf("transfer returned an unexpected value") - } - - if !transferred { - return fmt.Errorf("transfer not successful") - } - - return nil -}