Skip to content

Commit

Permalink
feat: add lockZRC20 capability to fungible keeper
Browse files Browse the repository at this point in the history
  • Loading branch information
fbac committed Oct 7, 2024
1 parent 1a32f05 commit 90a86d2
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 55 deletions.
75 changes: 29 additions & 46 deletions precompiles/bank/method_deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,33 +107,33 @@ func (c *Contract) deposit(

// Check for enough bank's allowance.
// function allowance(address owner, address spender) public view virtual override returns (uint256)
resAllowance, err := c.CallContract(
ctx,
&c.fungibleKeeper,
c.zrc20ABI,
zrc20Addr,
"allowance",
[]interface{}{caller, ContractAddress},
)
if err != nil {
return nil, &ptypes.ErrUnexpected{
When: "allowance",
Got: err.Error(),
}
}

allowance, ok := resAllowance[0].(*big.Int)
if !ok {
return nil, &ptypes.ErrUnexpected{
Got: "ZRC20 allowance returned an unexpected type",
}
}

if allowance.Cmp(amount) < 0 || allowance.Cmp(big.NewInt(0)) <= 0 {
return nil, &ptypes.ErrInvalidAmount{
Got: allowance.String(),
}
}
// resAllowance, err := c.CallContract(
// ctx,
// &c.fungibleKeeper,
// c.zrc20ABI,
// zrc20Addr,
// "allowance",
// []interface{}{caller, ContractAddress},
// )
// if err != nil {
// return nil, &ptypes.ErrUnexpected{
// When: "allowance",
// Got: err.Error(),
// }
// }

// allowance, ok := resAllowance[0].(*big.Int)
// if !ok {
// return nil, &ptypes.ErrUnexpected{
// Got: "ZRC20 allowance returned an unexpected type",
// }
// }

// if allowance.Cmp(amount) < 0 || allowance.Cmp(big.NewInt(0)) <= 0 {
// return nil, &ptypes.ErrInvalidAmount{
// Got: allowance.String(),
// }
// }

// The process of creating a new cosmos coin is:
// - Generate the new coin denom using ZRC20 address,
Expand All @@ -146,30 +146,13 @@ func (c *Contract) deposit(
}

// 2. Effect: subtract balance.
// function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool)
resTransferFrom, err := c.CallContract(
ctx,
&c.fungibleKeeper,
c.zrc20ABI,
zrc20Addr,
"transferFrom",
[]interface{}{caller, ContractAddress, amount},
)
if err != nil {
if err := c.fungibleKeeper.LockZRC20InBank(ctx, c.zrc20ABI, zrc20Addr, caller, amount); err != nil {
return nil, &ptypes.ErrUnexpected{
When: "transferFrom",
When: "LockZRC20InBank",
Got: err.Error(),
}
}

transferred, ok := resTransferFrom[0].(bool)
if !ok || !transferred {
return nil, &ptypes.ErrUnexpected{
When: "transferFrom",
Got: "transaction not successful",
}
}

// 3. Interactions: create cosmos coin and send.
if err := c.bankKeeper.MintCoins(ctx, types.ModuleName, coinSet); err != nil {
return nil, &ptypes.ErrUnexpected{
Expand Down
12 changes: 3 additions & 9 deletions precompiles/bank/method_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ func Test_Methods(t *testing.T) {
require.Error(t, err)
require.ErrorAs(
t,
ptypes.ErrInvalidAmount{
Got: "0",
ptypes.ErrInvalidCoin{
Empty: true,
},
err,
)
Expand Down Expand Up @@ -173,13 +173,7 @@ func Test_Methods(t *testing.T) {

success, err := ts.bankContract.Run(ts.mockEVM, ts.mockVMContract, false)
require.Error(t, err)
require.ErrorAs(
t,
ptypes.ErrInvalidAmount{
Got: "500",
},
err,
)
require.Contains(t, err.Error(), "unexpected error in LockZRC20InBank: invalid allowance, got: 500")

res, err := ts.bankABI.Methods[DepositMethodName].Outputs.Unpack(success)
require.NoError(t, err)
Expand Down
144 changes: 144 additions & 0 deletions x/fungible/keeper/lock_zrc20_bank.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package keeper

import (
"fmt"
"math/big"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)

const (
transferFrom = "transferFrom"
allowance = "allowance"
)

var (
bankAddress common.Address = common.HexToAddress("0x0000000000000000000000000000000000000067")
zeroAddress common.Address = common.HexToAddress("0x0000000000000000000000000000000000000000")
)

// LockZRC20InBank 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) LockZRC20InBank(
ctx sdk.Context,
zrc20ABI *abi.ABI,
zrc20Address, from common.Address,
amount *big.Int,
) error {
accAddress := sdk.AccAddress(bankAddress.Bytes())
if k.GetAuthKeeper().GetAccount(ctx, accAddress) == nil {
k.GetAuthKeeper().SetAccount(ctx, authtypes.NewBaseAccount(accAddress, nil, 0, 0))

Check warning on line 33 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L30-L33

Added lines #L30 - L33 were not covered by tests
}

if amount.Sign() <= 0 {
return fmt.Errorf("amount must be positive")

Check warning on line 37 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L36-L37

Added lines #L36 - L37 were not covered by tests
}

if from == zeroAddress {
return fmt.Errorf("from address cannot be zero")

Check warning on line 41 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L40-L41

Added lines #L40 - L41 were not covered by tests
}

if zrc20Address == zeroAddress {
return fmt.Errorf("zrc20 address cannot be zero")

Check warning on line 45 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L44-L45

Added lines #L44 - L45 were not covered by tests
}

if err := k.checkBankAllowance(ctx, zrc20ABI, from, zrc20Address, amount); err != nil {
return err

Check warning on line 49 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L48-L49

Added lines #L48 - L49 were not covered by tests
}

args := []interface{}{from, bankAddress, amount}
res, err := k.CallEVM(
ctx,
*zrc20ABI,
bankAddress,
zrc20Address,
big.NewInt(0),
nil,
true,
true,
transferFrom,
args...,
)
if err != nil {
return err

Check warning on line 66 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L52-L66

Added lines #L52 - L66 were not covered by tests
}

if res.VmError != "" {
return fmt.Errorf("%s", res.VmError)

Check warning on line 70 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L69-L70

Added lines #L69 - L70 were not covered by tests
}

ret, err := zrc20ABI.Methods[transferFrom].Outputs.Unpack(res.Ret)
if err != nil {
return err

Check warning on line 75 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L73-L75

Added lines #L73 - L75 were not covered by tests
}

transferred, ok := ret[0].(bool)
if !ok {
return fmt.Errorf("transferFrom returned an unexpected value")

Check warning on line 80 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L78-L80

Added lines #L78 - L80 were not covered by tests
}

if !transferred {
return fmt.Errorf("transferFrom not successful")

Check warning on line 84 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L83-L84

Added lines #L83 - L84 were not covered by tests
}

return nil

Check warning on line 87 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L87

Added line #L87 was not covered by tests
}

func (k Keeper) checkBankAllowance(
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")

Check warning on line 97 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L95-L97

Added lines #L95 - L97 were not covered by tests
}

if from == zeroAddress {
return fmt.Errorf("from address cannot be zero")

Check warning on line 101 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L100-L101

Added lines #L100 - L101 were not covered by tests
}

if zrc20Address == zeroAddress {
return fmt.Errorf("zrc20 address cannot be zero")

Check warning on line 105 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L104-L105

Added lines #L104 - L105 were not covered by tests
}

args := []interface{}{from, bankAddress}
res, err := k.CallEVM(
ctx,
*zrc20ABI,
bankAddress,
zrc20Address,
big.NewInt(0),
nil,
true,
true,
allowance,
args...,
)
if err != nil {
return err

Check warning on line 122 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L108-L122

Added lines #L108 - L122 were not covered by tests
}

if res.VmError != "" {
return fmt.Errorf("%s", res.VmError)

Check warning on line 126 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L125-L126

Added lines #L125 - L126 were not covered by tests
}

ret, err := zrc20ABI.Methods[allowance].Outputs.Unpack(res.Ret)
if err != nil {
return err

Check warning on line 131 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L129-L131

Added lines #L129 - L131 were not covered by tests
}

allowance, ok := ret[0].(*big.Int)
if !ok {
return fmt.Errorf("ZRC20 allowance returned an unexpected type")

Check warning on line 136 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L134-L136

Added lines #L134 - L136 were not covered by tests
}

if allowance.Cmp(amount) < 0 || allowance.Cmp(big.NewInt(0)) <= 0 {
return fmt.Errorf("invalid allowance, got: %s", allowance.String())

Check warning on line 140 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L139-L140

Added lines #L139 - L140 were not covered by tests
}

return nil

Check warning on line 143 in x/fungible/keeper/lock_zrc20_bank.go

View check run for this annotation

Codecov / codecov/patch

x/fungible/keeper/lock_zrc20_bank.go#L143

Added line #L143 was not covered by tests
}

0 comments on commit 90a86d2

Please sign in to comment.