Commit d7c2d167 authored by Ralph Pichler's avatar Ralph Pichler Committed by GitHub

chequebook: remove erc20 bindings (#1362)

parent aa8e5d36
......@@ -135,7 +135,6 @@ func InitChequebookService(
overlayEthAddress,
chequeSigner,
chequebook.NewSimpleSwapBindings,
chequebook.NewERC20Bindings,
)
if err != nil {
return nil, fmt.Errorf("chequebook init: %w", err)
......
......@@ -26,15 +26,3 @@ type SimpleSwapBindingFunc = func(common.Address, bind.ContractBackend) (SimpleS
func NewSimpleSwapBindings(address common.Address, backend bind.ContractBackend) (SimpleSwapBinding, error) {
return simpleswapfactory.NewERC20SimpleSwap(address, backend)
}
// ERC20Binding is the interface for the generated go bindings for ERC20
type ERC20Binding interface {
BalanceOf(*bind.CallOpts, common.Address) (*big.Int, error)
}
type ERC20BindingFunc = func(common.Address, bind.ContractBackend) (ERC20Binding, error)
// NewERC20Bindings generates the default go bindings
func NewERC20Bindings(address common.Address, backend bind.ContractBackend) (ERC20Binding, error) {
return simpleswapfactory.NewERC20(address, backend)
}
......@@ -14,6 +14,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/settlement/swap/erc20"
"github.com/ethersphere/bee/pkg/settlement/swap/transaction"
"github.com/ethersphere/bee/pkg/storage"
"github.com/ethersphere/sw3-bindings/v3/simpleswapfactory"
......@@ -36,7 +37,6 @@ var (
chequebookABI = transaction.ParseABIUnchecked(simpleswapfactory.ERC20SimpleSwapABI)
chequeCashedEventType = chequebookABI.Events["ChequeCashed"]
chequeBouncedEventType = chequebookABI.Events["ChequeBounced"]
erc20ABI = transaction.ParseABIUnchecked(simpleswapfactory.ERC20ABI)
)
// Service is the main interface for interacting with the nodes chequebook.
......@@ -70,8 +70,7 @@ type service struct {
chequebookInstance SimpleSwapBinding
ownerAddress common.Address
erc20Address common.Address
erc20Instance ERC20Binding
erc20Service erc20.Service
store storage.StateStorer
chequeSigner ChequeSigner
......@@ -79,25 +78,19 @@ type service struct {
}
// New creates a new chequebook service for the provided chequebook contract.
func New(backend transaction.Backend, transactionService transaction.Service, address, erc20Address, ownerAddress common.Address, store storage.StateStorer, chequeSigner ChequeSigner, simpleSwapBindingFunc SimpleSwapBindingFunc, erc20BindingFunc ERC20BindingFunc) (Service, error) {
func New(backend transaction.Backend, transactionService transaction.Service, address, ownerAddress common.Address, store storage.StateStorer, chequeSigner ChequeSigner, erc20Service erc20.Service, simpleSwapBindingFunc SimpleSwapBindingFunc) (Service, error) {
chequebookInstance, err := simpleSwapBindingFunc(address, backend)
if err != nil {
return nil, err
}
erc20Instance, err := erc20BindingFunc(erc20Address, backend)
if err != nil {
return nil, err
}
return &service{
backend: backend,
transactionService: transactionService,
address: address,
chequebookInstance: chequebookInstance,
ownerAddress: ownerAddress,
erc20Address: erc20Address,
erc20Instance: erc20Instance,
erc20Service: erc20Service,
store: store,
chequeSigner: chequeSigner,
totalIssuedReserved: big.NewInt(0),
......@@ -111,9 +104,7 @@ func (s *service) Address() common.Address {
// Deposit starts depositing erc20 token into the chequebook. This returns once the transactions has been broadcast.
func (s *service) Deposit(ctx context.Context, amount *big.Int) (hash common.Hash, err error) {
balance, err := s.erc20Instance.BalanceOf(&bind.CallOpts{
Context: ctx,
}, s.ownerAddress)
balance, err := s.erc20Service.BalanceOf(ctx, s.ownerAddress)
if err != nil {
return common.Hash{}, err
}
......@@ -123,25 +114,7 @@ func (s *service) Deposit(ctx context.Context, amount *big.Int) (hash common.Has
return common.Hash{}, ErrInsufficientFunds
}
callData, err := erc20ABI.Pack("transfer", s.address, amount)
if err != nil {
return common.Hash{}, err
}
request := &transaction.TxRequest{
To: &s.erc20Address,
Data: callData,
GasPrice: nil,
GasLimit: 0,
Value: big.NewInt(0),
}
txHash, err := s.transactionService.Send(ctx, request)
if err != nil {
return common.Hash{}, err
}
return txHash, nil
return s.erc20Service.Transfer(ctx, s.address, amount)
}
// Balance returns the token balance of the chequebook.
......
......@@ -36,14 +36,6 @@ func (m *simpleSwapBindingMock) PaidOut(o *bind.CallOpts, c common.Address) (*bi
return m.paidOut(o, c)
}
type erc20BindingMock struct {
balanceOf func(*bind.CallOpts, common.Address) (*big.Int, error)
}
func (m *erc20BindingMock) BalanceOf(o *bind.CallOpts, a common.Address) (*big.Int, error) {
return m.balanceOf(o, a)
}
type chequeSignerMock struct {
sign func(cheque *chequebook.Cheque) ([]byte, error)
}
......
......@@ -10,9 +10,9 @@ import (
"math/big"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/logging"
"github.com/ethersphere/bee/pkg/settlement/swap/erc20"
"github.com/ethersphere/bee/pkg/settlement/swap/transaction"
"github.com/ethersphere/bee/pkg/storage"
)
......@@ -20,6 +20,9 @@ import (
const (
chequebookKey = "swap_chequebook"
chequebookDeploymentKey = "swap_chequebook_transaction_deployment"
balanceCheckBackoffDuration = 20 * time.Second
balanceCheckMaxRetries = 10
)
func checkBalance(
......@@ -29,23 +32,12 @@ func checkBalance(
swapBackend transaction.Backend,
chainId int64,
overlayEthAddress common.Address,
erc20BindingFunc ERC20BindingFunc,
erc20Address common.Address,
backoffDuration time.Duration,
maxRetries uint64,
erc20Token erc20.Service,
) error {
timeoutCtx, cancel := context.WithTimeout(ctx, backoffDuration*time.Duration(maxRetries))
timeoutCtx, cancel := context.WithTimeout(ctx, balanceCheckBackoffDuration*time.Duration(balanceCheckMaxRetries))
defer cancel()
erc20Token, err := erc20BindingFunc(erc20Address, swapBackend)
if err != nil {
return err
}
for {
erc20Balance, err := erc20Token.BalanceOf(&bind.CallOpts{
Context: timeoutCtx,
}, overlayEthAddress)
erc20Balance, err := erc20Token.BalanceOf(timeoutCtx, overlayEthAddress)
if err != nil {
return err
}
......@@ -83,7 +75,7 @@ func checkBalance(
logger.Warningf("get your Goerli ETH and Goerli BZZ now via the bzzaar at https://bzz.ethswarm.org/?transaction=buy&amount=%d&slippage=30&receiver=0x%x", neededERC20, overlayEthAddress)
}
select {
case <-time.After(backoffDuration):
case <-time.After(balanceCheckBackoffDuration):
case <-timeoutCtx.Done():
if insufficientERC20 {
return fmt.Errorf("insufficient BZZ for initial deposit")
......@@ -111,7 +103,7 @@ func Init(
overlayEthAddress common.Address,
chequeSigner ChequeSigner,
simpleSwapBindingFunc SimpleSwapBindingFunc,
erc20BindingFunc ERC20BindingFunc) (chequebookService Service, err error) {
) (chequebookService Service, err error) {
// verify that the supplied factory is valid
err = chequebookFactory.VerifyBytecode(ctx)
if err != nil {
......@@ -123,6 +115,8 @@ func Init(
return nil, err
}
erc20Service := erc20.New(swapBackend, transactionService, erc20Address)
var chequebookAddress common.Address
err = stateStore.Get(chequebookKey, &chequebookAddress)
if err != nil {
......@@ -138,7 +132,7 @@ func Init(
if err == storage.ErrNotFound {
logger.Info("no chequebook found, deploying new one.")
if swapInitialDeposit.Cmp(big.NewInt(0)) != 0 {
err = checkBalance(ctx, logger, swapInitialDeposit, swapBackend, chainId, overlayEthAddress, erc20BindingFunc, erc20Address, 20*time.Second, 10)
err = checkBalance(ctx, logger, swapInitialDeposit, swapBackend, chainId, overlayEthAddress, erc20Service)
if err != nil {
return nil, err
}
......@@ -173,7 +167,7 @@ func Init(
return nil, err
}
chequebookService, err = New(swapBackend, transactionService, chequebookAddress, erc20Address, overlayEthAddress, stateStore, chequeSigner, simpleSwapBindingFunc, erc20BindingFunc)
chequebookService, err = New(swapBackend, transactionService, chequebookAddress, overlayEthAddress, stateStore, chequeSigner, erc20Service, simpleSwapBindingFunc)
if err != nil {
return nil, err
}
......@@ -194,7 +188,7 @@ func Init(
logger.Info("successfully deposited to chequebook")
}
} else {
chequebookService, err = New(swapBackend, transactionService, chequebookAddress, erc20Address, overlayEthAddress, stateStore, chequeSigner, simpleSwapBindingFunc, erc20BindingFunc)
chequebookService, err = New(swapBackend, transactionService, chequebookAddress, overlayEthAddress, stateStore, chequeSigner, erc20Service, simpleSwapBindingFunc)
if err != nil {
return nil, err
}
......
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package erc20
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/settlement/swap/transaction"
"github.com/ethersphere/sw3-bindings/v3/simpleswapfactory"
)
var (
erc20ABI = transaction.ParseABIUnchecked(simpleswapfactory.ERC20ABI)
errDecodeABI = errors.New("could not decode abi data")
)
type Service interface {
BalanceOf(ctx context.Context, address common.Address) (*big.Int, error)
Transfer(ctx context.Context, address common.Address, value *big.Int) (common.Hash, error)
}
type erc20Service struct {
backend transaction.Backend
transactionService transaction.Service
address common.Address
}
func New(backend transaction.Backend, transactionService transaction.Service, address common.Address) Service {
return &erc20Service{
backend: backend,
transactionService: transactionService,
address: address,
}
}
func (c *erc20Service) BalanceOf(ctx context.Context, address common.Address) (*big.Int, error) {
callData, err := erc20ABI.Pack("balanceOf", address)
if err != nil {
return nil, err
}
output, err := c.transactionService.Call(ctx, &transaction.TxRequest{
To: &c.address,
Data: callData,
})
if err != nil {
return nil, err
}
results, err := erc20ABI.Unpack("balanceOf", output)
if err != nil {
return nil, err
}
if len(results) != 1 {
return nil, errDecodeABI
}
balance, ok := abi.ConvertType(results[0], new(big.Int)).(*big.Int)
if !ok || balance == nil {
return nil, errDecodeABI
}
return balance, nil
}
func (c *erc20Service) Transfer(ctx context.Context, address common.Address, value *big.Int) (common.Hash, error) {
callData, err := erc20ABI.Pack("transfer", address, value)
if err != nil {
return common.Hash{}, err
}
request := &transaction.TxRequest{
To: &c.address,
Data: callData,
GasPrice: nil,
GasLimit: 0,
Value: big.NewInt(0),
}
txHash, err := c.transactionService.Send(ctx, request)
if err != nil {
return common.Hash{}, err
}
return txHash, nil
}
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package erc20_test
import (
"context"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/settlement/swap/erc20"
"github.com/ethersphere/bee/pkg/settlement/swap/transaction"
backendmock "github.com/ethersphere/bee/pkg/settlement/swap/transaction/backendmock"
transactionmock "github.com/ethersphere/bee/pkg/settlement/swap/transaction/mock"
"github.com/ethersphere/sw3-bindings/v3/simpleswapfactory"
)
var (
erc20ABI = transaction.ParseABIUnchecked(simpleswapfactory.ERC20ABI)
)
func TestBalanceOf(t *testing.T) {
erc20Address := common.HexToAddress("00")
account := common.HexToAddress("01")
expectedBalance := big.NewInt(100)
erc20 := erc20.New(
backendmock.New(),
transactionmock.New(
transactionmock.WithABICall(
&erc20ABI,
expectedBalance.FillBytes(make([]byte, 32)),
"balanceOf",
account,
),
),
erc20Address,
)
balance, err := erc20.BalanceOf(context.Background(), account)
if err != nil {
t.Fatal(err)
}
if expectedBalance.Cmp(balance) != 0 {
t.Fatalf("got wrong balance. wanted %d, got %d", expectedBalance, balance)
}
}
func TestTransfer(t *testing.T) {
address := common.HexToAddress("0xabcd")
account := common.HexToAddress("01")
value := big.NewInt(20)
txHash := common.HexToHash("0xdddd")
erc20 := erc20.New(
backendmock.New(),
transactionmock.New(
transactionmock.WithABISend(&erc20ABI, txHash, address, big.NewInt(0), "transfer", account, value),
),
address,
)
returnedTxHash, err := erc20.Transfer(context.Background(), account, value)
if err != nil {
t.Fatal(err)
}
if txHash != returnedTxHash {
t.Fatalf("returned wrong transaction hash. wanted %v, got %v", txHash, returnedTxHash)
}
}
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mock
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/settlement/swap/erc20"
)
type Service struct {
balanceOfFunc func(ctx context.Context, address common.Address) (*big.Int, error)
transferFunc func(ctx context.Context, address common.Address, value *big.Int) (common.Hash, error)
}
func WithBalanceOfFunc(f func(ctx context.Context, address common.Address) (*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.balanceOfFunc = f
})
}
func WithTransferFunc(f func(ctx context.Context, address common.Address, value *big.Int) (common.Hash, error)) Option {
return optionFunc(func(s *Service) {
s.transferFunc = f
})
}
func New(opts ...Option) erc20.Service {
mock := new(Service)
for _, o := range opts {
o.apply(mock)
}
return mock
}
func (s *Service) BalanceOf(ctx context.Context, address common.Address) (*big.Int, error) {
if s.balanceOfFunc != nil {
return s.balanceOfFunc(ctx, address)
}
return big.NewInt(0), errors.New("Error")
}
func (s *Service) Transfer(ctx context.Context, address common.Address, value *big.Int) (common.Hash, error) {
if s.transferFunc != nil {
return s.transferFunc(ctx, address, value)
}
return common.Hash{}, errors.New("Error")
}
// Option is the option passed to the mock Chequebook service
type Option interface {
apply(*Service)
}
type optionFunc func(*Service)
func (f optionFunc) apply(r *Service) { f(r) }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment