Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mybee
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
mybee
Commits
b3bc0460
Unverified
Commit
b3bc0460
authored
Sep 21, 2020
by
Ralph Pichler
Committed by
GitHub
Sep 21, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chequebook deployment (#703)
parent
db5a1bba
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1553 additions
and
0 deletions
+1553
-0
cmd.go
cmd/bee/cmd/cmd.go
+8
-0
start.go
cmd/bee/cmd/start.go
+4
-0
go.mod
go.mod
+2
-0
go.sum
go.sum
+2
-0
clef.go
pkg/crypto/clef/clef.go
+15
-0
clef_test.go
pkg/crypto/clef/clef_test.go
+6
-0
signer.go
pkg/crypto/signer.go
+42
-0
signer_test.go
pkg/crypto/signer_test.go
+66
-0
node.go
pkg/node/node.go
+55
-0
bindings.go
pkg/settlement/swap/chequebook/bindings.go
+52
-0
chequebook.go
pkg/settlement/swap/chequebook/chequebook.go
+137
-0
chequebook_test.go
pkg/settlement/swap/chequebook/chequebook_test.go
+223
-0
common_test.go
pkg/settlement/swap/chequebook/common_test.go
+112
-0
factory.go
pkg/settlement/swap/chequebook/factory.go
+158
-0
factory_test.go
pkg/settlement/swap/chequebook/factory_test.go
+278
-0
init.go
pkg/settlement/swap/chequebook/init.go
+99
-0
transaction.go
pkg/settlement/swap/chequebook/transaction.go
+150
-0
transaction_test.go
pkg/settlement/swap/chequebook/transaction_test.go
+144
-0
No files found.
cmd/bee/cmd/cmd.go
View file @
b3bc0460
...
...
@@ -44,6 +44,10 @@ const (
optionNameGatewayMode
=
"gateway-mode"
optionNameClefSignerEnable
=
"clef-signer-enable"
optionNameClefSignerEndpoint
=
"clef-signer-endpoint"
optionNameSwapEndpoint
=
"swap-endpoint"
optionNameSwapFactoryAddress
=
"swap-factory-address"
optionNameSwapInitialDeposit
=
"swap-initial-deposit"
optionNameSwapEnable
=
"swap-enable"
)
func
init
()
{
...
...
@@ -190,4 +194,8 @@ func (c *command) setAllFlags(cmd *cobra.Command) {
cmd
.
Flags
()
.
Bool
(
optionNameGatewayMode
,
false
,
"disable a set of sensitive features in the api"
)
cmd
.
Flags
()
.
Bool
(
optionNameClefSignerEnable
,
false
,
"enable clef signer"
)
cmd
.
Flags
()
.
String
(
optionNameClefSignerEndpoint
,
""
,
"clef signer endpoint"
)
cmd
.
Flags
()
.
String
(
optionNameSwapEndpoint
,
"http://localhost:8545"
,
"swap ethereum blockchain endpoint"
)
cmd
.
Flags
()
.
String
(
optionNameSwapFactoryAddress
,
""
,
"swap factory address"
)
cmd
.
Flags
()
.
Uint64
(
optionNameSwapInitialDeposit
,
0
,
"initial deposit if deploying a new chequebook"
)
cmd
.
Flags
()
.
Bool
(
optionNameSwapEnable
,
false
,
"enable swap"
)
}
cmd/bee/cmd/start.go
View file @
b3bc0460
...
...
@@ -202,6 +202,10 @@ Welcome to the Swarm.... Bzzz Bzzzz Bzzzz
PaymentTolerance
:
c
.
config
.
GetUint64
(
optionNamePaymentTolerance
),
ResolverConnectionCfgs
:
resolverCfgs
,
GatewayMode
:
c
.
config
.
GetBool
(
optionNameGatewayMode
),
SwapEndpoint
:
c
.
config
.
GetString
(
optionNameSwapEndpoint
),
SwapFactoryAddress
:
c
.
config
.
GetString
(
optionNameSwapFactoryAddress
),
SwapInitialDeposit
:
c
.
config
.
GetUint64
(
optionNameSwapInitialDeposit
),
SwapEnable
:
c
.
config
.
GetBool
(
optionNameSwapEnable
),
})
if
err
!=
nil
{
return
err
...
...
go.mod
View file @
b3bc0460
...
...
@@ -10,6 +10,7 @@ require (
github.com/ethereum/go-ethereum v1.9.20
github.com/ethersphere/bmt v0.1.2
github.com/ethersphere/manifest v0.2.0
github.com/ethersphere/sw3-bindings/v2 v2.0.0
github.com/gogo/protobuf v1.3.1
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
...
...
@@ -57,6 +58,7 @@ require (
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/mod v0.3.0 // indirect
golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect
golang.org/x/text v0.3.3 // indirect
...
...
go.sum
View file @
b3bc0460
...
...
@@ -167,6 +167,8 @@ github.com/ethersphere/bmt v0.1.2 h1:FEuvQY9xuK+rDp3VwDVyde8T396Matv/u9PdtKa2r9Q
github.com/ethersphere/bmt v0.1.2/go.mod h1:fqRBDmYwn3lX2MH4lkImXQgFWeNP8ikLkS/hgi/HRws=
github.com/ethersphere/manifest v0.2.0 h1:HD2ufiIaw/5Vgrl4XyeGduDJ5tn50wIhqMQoWdT2GME=
github.com/ethersphere/manifest v0.2.0/go.mod h1:ygAx0KLhXYmKqsjUab95RCbXf8UcO7yMDjyfP0lY76Y=
github.com/ethersphere/sw3-bindings/v2 v2.0.0 h1:uc+wBqEMMq7c4NWj+MSkKkkpObgrUYxfAxz6FYJWkI4=
github.com/ethersphere/sw3-bindings/v2 v2.0.0/go.mod h1:OA34yk7ludjNag+yBDY9Gp3czWoFUVMsiK7gUXnZ26U=
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
...
...
pkg/crypto/clef/clef.go
View file @
b3bc0460
...
...
@@ -7,11 +7,14 @@ package clef
import
(
"crypto/ecdsa"
"errors"
"math/big"
"os"
"path/filepath"
"runtime"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/crypto"
)
...
...
@@ -23,6 +26,7 @@ var (
// ExternalSignerInterface is the interface for the clef client from go-ethereum
type
ExternalSignerInterface
interface
{
SignData
(
account
accounts
.
Account
,
mimeType
string
,
data
[]
byte
)
([]
byte
,
error
)
SignTx
(
account
accounts
.
Account
,
tx
*
types
.
Transaction
,
chainID
*
big
.
Int
)
(
*
types
.
Transaction
,
error
)
Accounts
()
[]
accounts
.
Account
}
...
...
@@ -94,3 +98,14 @@ func (c *clefSigner) PublicKey() (*ecdsa.PublicKey, error) {
func
(
c
*
clefSigner
)
Sign
(
data
[]
byte
)
([]
byte
,
error
)
{
return
c
.
clef
.
SignData
(
c
.
account
,
accounts
.
MimetypeTextPlain
,
data
)
}
// SignTx signs an ethereum transaction
func
(
c
*
clefSigner
)
SignTx
(
transaction
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
// chainId is nil here because it is set on the clef side
return
c
.
clef
.
SignTx
(
c
.
account
,
transaction
,
nil
)
}
// EthereumAddress returns the ethereum address this signer uses
func
(
c
*
clefSigner
)
EthereumAddress
()
(
common
.
Address
,
error
)
{
return
c
.
account
.
Address
,
nil
}
pkg/crypto/clef/clef_test.go
View file @
b3bc0460
...
...
@@ -8,10 +8,12 @@ import (
"bytes"
"crypto/ecdsa"
"errors"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/crypto"
"github.com/ethersphere/bee/pkg/crypto/clef"
)
...
...
@@ -36,6 +38,10 @@ func (m *mockClef) Accounts() []accounts.Account {
return
m
.
accounts
}
func
(
m
*
mockClef
)
SignTx
(
account
accounts
.
Account
,
transaction
*
types
.
Transaction
,
chainId
*
big
.
Int
)
(
*
types
.
Transaction
,
error
)
{
return
nil
,
nil
}
func
TestNewClefSigner
(
t
*
testing
.
T
)
{
ethAddress
:=
common
.
HexToAddress
(
"0x31415b599f636129AD03c196cef9f8f8b184D5C7"
)
testSignature
:=
make
([]
byte
,
65
)
...
...
pkg/crypto/signer.go
View file @
b3bc0460
...
...
@@ -10,6 +10,8 @@ import (
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
var
(
...
...
@@ -17,8 +19,14 @@ var (
)
type
Signer
interface
{
// Sign signs data with ethereum prefix (eip191 type 0x45)
Sign
(
data
[]
byte
)
([]
byte
,
error
)
// SignTx signs an ethereum transaction
SignTx
(
transaction
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
// PublicKey returns the public key this signer uses
PublicKey
()
(
*
ecdsa
.
PublicKey
,
error
)
// EthereumAddress returns the ethereum address this signer uses
EthereumAddress
()
(
common
.
Address
,
error
)
}
// addEthereumPrefix adds the ethereum prefix to the data
...
...
@@ -61,10 +69,12 @@ func NewDefaultSigner(key *ecdsa.PrivateKey) Signer {
}
}
// PublicKey returns the public key this signer uses
func
(
d
*
defaultSigner
)
PublicKey
()
(
*
ecdsa
.
PublicKey
,
error
)
{
return
&
d
.
key
.
PublicKey
,
nil
}
// Sign signs data with ethereum prefix (eip191 type 0x45)
func
(
d
*
defaultSigner
)
Sign
(
data
[]
byte
)
(
signature
[]
byte
,
err
error
)
{
hash
,
err
:=
hashWithEthereumPrefix
(
data
)
if
err
!=
nil
{
...
...
@@ -82,3 +92,35 @@ func (d *defaultSigner) Sign(data []byte) (signature []byte, err error) {
signature
[
64
]
=
v
return
signature
,
nil
}
// SignTx signs an ethereum transaction
func
(
d
*
defaultSigner
)
SignTx
(
transaction
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
hash
:=
(
&
types
.
HomesteadSigner
{})
.
Hash
(
transaction
)
.
Bytes
()
// isCompressedKey is false here so we get the expected v value (27 or 28)
signature
,
err
:=
btcec
.
SignCompact
(
btcec
.
S256
(),
(
*
btcec
.
PrivateKey
)(
d
.
key
),
hash
,
false
)
if
err
!=
nil
{
return
nil
,
err
}
// Convert to Ethereum signature format with 'recovery id' v at the end.
v
:=
signature
[
0
]
copy
(
signature
,
signature
[
1
:
])
// v value needs to be adjusted by 27 as transaction.WithSignature expects it to be 0 or 1
signature
[
64
]
=
v
-
27
return
transaction
.
WithSignature
(
&
types
.
HomesteadSigner
{},
signature
)
}
// EthereumAddress returns the ethereum address this signer uses
func
(
d
*
defaultSigner
)
EthereumAddress
()
(
common
.
Address
,
error
)
{
publicKey
,
err
:=
d
.
PublicKey
()
if
err
!=
nil
{
return
common
.
Address
{},
err
}
eth
,
err
:=
NewEthereumAddress
(
*
publicKey
)
if
err
!=
nil
{
return
common
.
Address
{},
err
}
var
ethAddress
common
.
Address
copy
(
ethAddress
[
:
],
eth
)
return
ethAddress
,
nil
}
pkg/crypto/signer_test.go
View file @
b3bc0460
...
...
@@ -5,9 +5,14 @@
package
crypto_test
import
(
"encoding/hex"
"errors"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/crypto"
)
...
...
@@ -56,3 +61,64 @@ func TestDefaultSigner(t *testing.T) {
}
})
}
func
TestDefaultSignerEthereumAddress
(
t
*
testing
.
T
)
{
data
,
err
:=
hex
.
DecodeString
(
"634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
privKey
,
err
:=
crypto
.
DecodeSecp256k1PrivateKey
(
data
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
signer
:=
crypto
.
NewDefaultSigner
(
privKey
)
ethAddress
,
err
:=
signer
.
EthereumAddress
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
expected
:=
common
.
HexToAddress
(
"8d3766440f0d7b949a5e32995d09619a7f86e632"
)
if
ethAddress
!=
expected
{
t
.
Fatalf
(
"wrong signature. expected %x, got %x"
,
expected
,
ethAddress
)
}
}
func
TestDefaultSignerSignTx
(
t
*
testing
.
T
)
{
data
,
err
:=
hex
.
DecodeString
(
"634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
privKey
,
err
:=
crypto
.
DecodeSecp256k1PrivateKey
(
data
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
signer
:=
crypto
.
NewDefaultSigner
(
privKey
)
beneficiary
:=
common
.
HexToAddress
(
"8d3766440f0d7b949a5e32995d09619a7f86e632"
)
tx
,
err
:=
signer
.
SignTx
(
types
.
NewTransaction
(
0
,
beneficiary
,
big
.
NewInt
(
0
),
21000
,
big
.
NewInt
(
1
),
[]
byte
{
1
}))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
expectedR
:=
math
.
MustParseBig256
(
"0x28815033e9b5b7ec32e40e3c90b6cd499c12de8a7da261fdad8b800c845b88ef"
)
expectedS
:=
math
.
MustParseBig256
(
"0x71f1c08f754ee36e0c9743a2240d4b6640ea4d78c8dc2d83a599bdcf80ef9d5f"
)
expectedV
:=
math
.
MustParseBig256
(
"0x1c"
)
v
,
r
,
s
:=
tx
.
RawSignatureValues
()
if
expectedV
.
Cmp
(
v
)
!=
0
{
t
.
Fatalf
(
"wrong v value. expected %x, got %x"
,
expectedV
,
v
)
}
if
expectedR
.
Cmp
(
r
)
!=
0
{
t
.
Fatalf
(
"wrong r value. expected %x, got %x"
,
expectedR
,
r
)
}
if
expectedS
.
Cmp
(
s
)
!=
0
{
t
.
Fatalf
(
"wrong s value. expected %x, got %x"
,
expectedS
,
s
)
}
}
pkg/node/node.go
View file @
b3bc0460
...
...
@@ -6,6 +6,7 @@ package node
import
(
"context"
"errors"
"fmt"
"io"
"log"
...
...
@@ -14,6 +15,8 @@ import (
"path/filepath"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethersphere/bee/pkg/accounting"
"github.com/ethersphere/bee/pkg/addressbook"
"github.com/ethersphere/bee/pkg/api"
...
...
@@ -39,6 +42,7 @@ import (
"github.com/ethersphere/bee/pkg/resolver/multiresolver"
"github.com/ethersphere/bee/pkg/retrieval"
"github.com/ethersphere/bee/pkg/settlement/pseudosettle"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
"github.com/ethersphere/bee/pkg/soc"
"github.com/ethersphere/bee/pkg/statestore/leveldb"
mockinmem
"github.com/ethersphere/bee/pkg/statestore/mock"
...
...
@@ -94,6 +98,10 @@ type Options struct {
PaymentTolerance
uint64
ResolverConnectionCfgs
[]
multiresolver
.
ConnectionConfig
GatewayMode
bool
SwapEndpoint
string
SwapFactoryAddress
string
SwapInitialDeposit
uint64
SwapEnable
bool
}
func
NewBee
(
addr
string
,
swarmAddress
swarm
.
Address
,
keystore
keystore
.
Service
,
signer
crypto
.
Signer
,
networkID
uint64
,
logger
logging
.
Logger
,
o
Options
)
(
*
Bee
,
error
)
{
...
...
@@ -138,6 +146,53 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service,
b
.
stateStoreCloser
=
stateStore
addressbook
:=
addressbook
.
New
(
stateStore
)
if
o
.
SwapEnable
{
swapBackend
,
err
:=
ethclient
.
Dial
(
o
.
SwapEndpoint
)
if
err
!=
nil
{
return
nil
,
err
}
transactionService
,
err
:=
chequebook
.
NewTransactionService
(
logger
,
swapBackend
,
signer
)
if
err
!=
nil
{
return
nil
,
err
}
overlayEthAddress
,
err
:=
signer
.
EthereumAddress
()
if
err
!=
nil
{
return
nil
,
err
}
// print ethereum address so users know which address we need to fund
logger
.
Infof
(
"using ethereum address %x"
,
overlayEthAddress
)
// TODO: factory address discovery for well-known networks (goerli for beta)
if
o
.
SwapFactoryAddress
==
""
{
return
nil
,
errors
.
New
(
"no known factory address"
)
}
else
if
!
common
.
IsHexAddress
(
o
.
SwapFactoryAddress
)
{
return
nil
,
errors
.
New
(
"invalid factory address"
)
}
chequebookFactory
,
err
:=
chequebook
.
NewFactory
(
swapBackend
,
transactionService
,
common
.
HexToAddress
(
o
.
SwapFactoryAddress
),
chequebook
.
NewSimpleSwapFactoryBindingFunc
)
if
err
!=
nil
{
return
nil
,
err
}
// initialize chequebook logic
// return value is ignored because we don't do anything yet after initialization. this will be passed into swap settlement.
_
,
err
=
chequebook
.
Init
(
p2pCtx
,
chequebookFactory
,
stateStore
,
logger
,
o
.
SwapInitialDeposit
,
transactionService
,
swapBackend
,
overlayEthAddress
,
chequebook
.
NewSimpleSwapBindings
,
chequebook
.
NewERC20Bindings
)
if
err
!=
nil
{
return
nil
,
err
}
}
p2ps
,
err
:=
libp2p
.
New
(
p2pCtx
,
signer
,
networkID
,
swarmAddress
,
addr
,
addressbook
,
stateStore
,
logger
,
tracer
,
libp2p
.
Options
{
PrivateKey
:
libp2pPrivateKey
,
NATAddr
:
o
.
NATAddr
,
...
...
pkg/settlement/swap/chequebook/bindings.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook
import
(
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/sw3-bindings/v2/simpleswapfactory"
)
// SimpleSwapBinding is the interface for the generated go bindings for ERC20SimpleSwap
type
SimpleSwapBinding
interface
{
Balance
(
*
bind
.
CallOpts
)
(
*
big
.
Int
,
error
)
}
type
SimpleSwapBindingFunc
=
func
(
common
.
Address
,
bind
.
ContractBackend
)
(
SimpleSwapBinding
,
error
)
// NewSimpleSwapBindings generates the default go bindings
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
)
}
// SimpleSwapFactoryBinding is the interface for the generated go bindings for SimpleSwapFactory
type
SimpleSwapFactoryBinding
interface
{
ParseSimpleSwapDeployed
(
types
.
Log
)
(
*
simpleswapfactory
.
SimpleSwapFactorySimpleSwapDeployed
,
error
)
DeployedContracts
(
*
bind
.
CallOpts
,
common
.
Address
)
(
bool
,
error
)
ERC20Address
(
*
bind
.
CallOpts
)
(
common
.
Address
,
error
)
}
type
SimpleSwapFactoryBindingFunc
=
func
(
common
.
Address
,
bind
.
ContractBackend
)
(
SimpleSwapFactoryBinding
,
error
)
// NewSimpleSwapFactoryBindingFunc generates the default go bindings
func
NewSimpleSwapFactoryBindingFunc
(
address
common
.
Address
,
backend
bind
.
ContractBackend
)
(
SimpleSwapFactoryBinding
,
error
)
{
return
simpleswapfactory
.
NewSimpleSwapFactory
(
address
,
backend
)
}
pkg/settlement/swap/chequebook/chequebook.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook
import
(
"context"
"errors"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/sw3-bindings/v2/simpleswapfactory"
)
// Service is the main interface for interacting with the nodes chequebook
type
Service
interface
{
// Deposit starts depositing erc20 token into the chequebook. This returns once the transactions has been broadcast.
Deposit
(
ctx
context
.
Context
,
amount
*
big
.
Int
)
(
hash
common
.
Hash
,
err
error
)
// WaitForDeposit waits for the deposit transaction to confirm and verifies the result
WaitForDeposit
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
error
// Balance returns the token balance of the chequebook
Balance
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
// Address returns the address of the used chequebook contract
Address
()
common
.
Address
}
type
service
struct
{
backend
Backend
transactionService
TransactionService
address
common
.
Address
chequebookABI
abi
.
ABI
chequebookInstance
SimpleSwapBinding
ownerAddress
common
.
Address
erc20Address
common
.
Address
erc20ABI
abi
.
ABI
erc20Instance
ERC20Binding
}
// New creates a new chequebook service for the provided chequebook contract
func
New
(
backend
Backend
,
transactionService
TransactionService
,
address
,
erc20Address
,
ownerAddress
common
.
Address
,
simpleSwapBindingFunc
SimpleSwapBindingFunc
,
erc20BindingFunc
ERC20BindingFunc
)
(
Service
,
error
)
{
chequebookABI
,
err
:=
abi
.
JSON
(
strings
.
NewReader
(
simpleswapfactory
.
ERC20SimpleSwapABI
))
if
err
!=
nil
{
return
nil
,
err
}
erc20ABI
,
err
:=
abi
.
JSON
(
strings
.
NewReader
(
simpleswapfactory
.
ERC20ABI
))
if
err
!=
nil
{
return
nil
,
err
}
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
,
chequebookABI
:
chequebookABI
,
chequebookInstance
:
chequebookInstance
,
ownerAddress
:
ownerAddress
,
erc20Address
:
erc20Address
,
erc20ABI
:
erc20ABI
,
erc20Instance
:
erc20Instance
,
},
nil
}
// Address returns the address of the used chequebook contract
func
(
s
*
service
)
Address
()
common
.
Address
{
return
s
.
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
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
// check we can afford this so we don't waste gas
if
balance
.
Cmp
(
amount
)
<
0
{
return
common
.
Hash
{},
errors
.
New
(
"insufficient token balance"
)
}
callData
,
err
:=
s
.
erc20ABI
.
Pack
(
"transfer"
,
s
.
address
,
amount
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
request
:=
&
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
}
// Balance returns the token balance of the chequebook
func
(
s
*
service
)
Balance
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
{
return
s
.
chequebookInstance
.
Balance
(
&
bind
.
CallOpts
{
Context
:
ctx
,
})
}
// WaitForDeposit waits for the deposit transaction to confirm and verifies the result
func
(
s
*
service
)
WaitForDeposit
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
error
{
receipt
,
err
:=
s
.
transactionService
.
WaitForReceipt
(
ctx
,
txHash
)
if
err
!=
nil
{
return
err
}
if
receipt
.
Status
!=
1
{
return
ErrTransactionReverted
}
return
nil
}
pkg/settlement/swap/chequebook/chequebook_test.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook_test
import
(
"context"
"errors"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
)
func
newTestChequebook
(
t
*
testing
.
T
,
backend
chequebook
.
Backend
,
transactionService
chequebook
.
TransactionService
,
address
common
.
Address
,
erc20address
common
.
Address
,
ownerAdress
common
.
Address
,
simpleSwapBinding
chequebook
.
SimpleSwapBinding
,
erc20Binding
chequebook
.
ERC20Binding
)
(
chequebook
.
Service
,
error
)
{
return
chequebook
.
New
(
backend
,
transactionService
,
address
,
erc20address
,
ownerAdress
,
func
(
addr
common
.
Address
,
b
bind
.
ContractBackend
)
(
chequebook
.
SimpleSwapBinding
,
error
)
{
if
addr
!=
address
{
t
.
Fatalf
(
"initialised binding with wrong address. wanted %x, got %x"
,
address
,
addr
)
}
if
b
!=
backend
{
t
.
Fatal
(
"initialised binding with wrong backend"
)
}
return
simpleSwapBinding
,
nil
},
func
(
addr
common
.
Address
,
b
bind
.
ContractBackend
)
(
chequebook
.
ERC20Binding
,
error
)
{
if
addr
!=
erc20address
{
t
.
Fatalf
(
"initialised binding with wrong address. wanted %x, got %x"
,
erc20address
,
addr
)
}
if
b
!=
backend
{
t
.
Fatal
(
"initialised binding with wrong backend"
)
}
return
erc20Binding
,
nil
},
)
}
func
TestChequebookAddress
(
t
*
testing
.
T
)
{
address
:=
common
.
HexToAddress
(
"0xabcd"
)
erc20address
:=
common
.
HexToAddress
(
"0xefff"
)
ownerAdress
:=
common
.
HexToAddress
(
"0xfff"
)
chequebookService
,
err
:=
newTestChequebook
(
t
,
&
backendMock
{},
&
transactionServiceMock
{},
address
,
erc20address
,
ownerAdress
,
&
simpleSwapBindingMock
{},
&
erc20BindingMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
chequebookService
.
Address
()
!=
address
{
t
.
Fatalf
(
"returned wrong address. wanted %x, got %x"
,
address
,
chequebookService
.
Address
())
}
}
func
TestChequebookBalance
(
t
*
testing
.
T
)
{
address
:=
common
.
HexToAddress
(
"0xabcd"
)
erc20address
:=
common
.
HexToAddress
(
"0xefff"
)
ownerAdress
:=
common
.
HexToAddress
(
"0xfff"
)
balance
:=
big
.
NewInt
(
10
)
chequebookService
,
err
:=
newTestChequebook
(
t
,
&
backendMock
{},
&
transactionServiceMock
{},
address
,
erc20address
,
ownerAdress
,
&
simpleSwapBindingMock
{
balance
:
func
(
*
bind
.
CallOpts
)
(
*
big
.
Int
,
error
)
{
return
balance
,
nil
},
},
&
erc20BindingMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
returnedBalance
,
err
:=
chequebookService
.
Balance
(
context
.
Background
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
returnedBalance
.
Cmp
(
balance
)
!=
0
{
t
.
Fatalf
(
"returned wrong balance. wanted %d, got %d"
,
balance
,
returnedBalance
)
}
}
func
TestChequebookDeposit
(
t
*
testing
.
T
)
{
address
:=
common
.
HexToAddress
(
"0xabcd"
)
erc20address
:=
common
.
HexToAddress
(
"0xefff"
)
ownerAdress
:=
common
.
HexToAddress
(
"0xfff"
)
balance
:=
big
.
NewInt
(
30
)
depositAmount
:=
big
.
NewInt
(
20
)
txHash
:=
common
.
HexToHash
(
"0xdddd"
)
chequebookService
,
err
:=
newTestChequebook
(
t
,
&
backendMock
{},
&
transactionServiceMock
{
send
:
func
(
c
context
.
Context
,
request
*
chequebook
.
TxRequest
)
(
common
.
Hash
,
error
)
{
if
request
.
To
!=
erc20address
{
t
.
Fatalf
(
"sending to wrong contract. wanted %x, got %x"
,
erc20address
,
request
.
To
)
}
if
request
.
Value
.
Cmp
(
big
.
NewInt
(
0
))
!=
0
{
t
.
Fatal
(
"sending ether to token contract"
)
}
return
txHash
,
nil
},
},
address
,
erc20address
,
ownerAdress
,
&
simpleSwapBindingMock
{},
&
erc20BindingMock
{
balanceOf
:
func
(
b
*
bind
.
CallOpts
,
addr
common
.
Address
)
(
*
big
.
Int
,
error
)
{
if
addr
!=
ownerAdress
{
t
.
Fatalf
(
"looking up balance of wrong account. wanted %x, got %x"
,
ownerAdress
,
addr
)
}
return
balance
,
nil
},
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
returnedTxHash
,
err
:=
chequebookService
.
Deposit
(
context
.
Background
(),
depositAmount
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
txHash
!=
returnedTxHash
{
t
.
Fatalf
(
"returned wrong transaction hash. wanted %v, got %v"
,
txHash
,
returnedTxHash
)
}
}
func
TestChequebookWaitForDeposit
(
t
*
testing
.
T
)
{
address
:=
common
.
HexToAddress
(
"0xabcd"
)
erc20address
:=
common
.
HexToAddress
(
"0xefff"
)
ownerAdress
:=
common
.
HexToAddress
(
"0xfff"
)
txHash
:=
common
.
HexToHash
(
"0xdddd"
)
chequebookService
,
err
:=
newTestChequebook
(
t
,
&
backendMock
{},
&
transactionServiceMock
{
waitForReceipt
:
func
(
ctx
context
.
Context
,
tx
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
if
tx
!=
txHash
{
t
.
Fatalf
(
"waiting for wrong transaction. wanted %x, got %x"
,
txHash
,
tx
)
}
return
&
types
.
Receipt
{
Status
:
1
,
},
nil
},
},
address
,
erc20address
,
ownerAdress
,
&
simpleSwapBindingMock
{},
&
erc20BindingMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
chequebookService
.
WaitForDeposit
(
context
.
Background
(),
txHash
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
func
TestChequebookWaitForDepositReverted
(
t
*
testing
.
T
)
{
address
:=
common
.
HexToAddress
(
"0xabcd"
)
erc20address
:=
common
.
HexToAddress
(
"0xefff"
)
ownerAdress
:=
common
.
HexToAddress
(
"0xfff"
)
txHash
:=
common
.
HexToHash
(
"0xdddd"
)
chequebookService
,
err
:=
newTestChequebook
(
t
,
&
backendMock
{},
&
transactionServiceMock
{
waitForReceipt
:
func
(
ctx
context
.
Context
,
tx
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
if
tx
!=
txHash
{
t
.
Fatalf
(
"waiting for wrong transaction. wanted %x, got %x"
,
txHash
,
tx
)
}
return
&
types
.
Receipt
{
Status
:
0
,
},
nil
},
},
address
,
erc20address
,
ownerAdress
,
&
simpleSwapBindingMock
{},
&
erc20BindingMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
chequebookService
.
WaitForDeposit
(
context
.
Background
(),
txHash
)
if
err
==
nil
{
t
.
Fatal
(
"expected reverted error"
)
}
if
!
errors
.
Is
(
err
,
chequebook
.
ErrTransactionReverted
)
{
t
.
Fatalf
(
"wrong error. wanted %v, got %v"
,
chequebook
.
ErrTransactionReverted
,
err
)
}
}
pkg/settlement/swap/chequebook/common_test.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook_test
import
(
"context"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
"github.com/ethersphere/sw3-bindings/v2/simpleswapfactory"
)
type
backendMock
struct
{
codeAt
func
(
ctx
context
.
Context
,
contract
common
.
Address
,
blockNumber
*
big
.
Int
)
([]
byte
,
error
)
sendTransaction
func
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
suggestGasPrice
func
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
estimateGas
func
(
ctx
context
.
Context
,
call
ethereum
.
CallMsg
)
(
gas
uint64
,
err
error
)
transactionReceipt
func
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
pendingNonceAt
func
(
ctx
context
.
Context
,
account
common
.
Address
)
(
uint64
,
error
)
}
func
(
m
*
backendMock
)
CodeAt
(
ctx
context
.
Context
,
contract
common
.
Address
,
blockNumber
*
big
.
Int
)
([]
byte
,
error
)
{
return
m
.
codeAt
(
ctx
,
contract
,
blockNumber
)
}
func
(
*
backendMock
)
CallContract
(
ctx
context
.
Context
,
call
ethereum
.
CallMsg
,
blockNumber
*
big
.
Int
)
([]
byte
,
error
)
{
panic
(
"not implemented"
)
}
func
(
*
backendMock
)
PendingCodeAt
(
ctx
context
.
Context
,
account
common
.
Address
)
([]
byte
,
error
)
{
panic
(
"not implemented"
)
}
func
(
m
*
backendMock
)
PendingNonceAt
(
ctx
context
.
Context
,
account
common
.
Address
)
(
uint64
,
error
)
{
return
m
.
pendingNonceAt
(
ctx
,
account
)
}
func
(
m
*
backendMock
)
SuggestGasPrice
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
{
return
m
.
suggestGasPrice
(
ctx
)
}
func
(
m
*
backendMock
)
EstimateGas
(
ctx
context
.
Context
,
call
ethereum
.
CallMsg
)
(
gas
uint64
,
err
error
)
{
return
m
.
estimateGas
(
ctx
,
call
)
}
func
(
m
*
backendMock
)
SendTransaction
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
{
return
m
.
sendTransaction
(
ctx
,
tx
)
}
func
(
*
backendMock
)
FilterLogs
(
ctx
context
.
Context
,
query
ethereum
.
FilterQuery
)
([]
types
.
Log
,
error
)
{
panic
(
"not implemented"
)
}
func
(
*
backendMock
)
SubscribeFilterLogs
(
ctx
context
.
Context
,
query
ethereum
.
FilterQuery
,
ch
chan
<-
types
.
Log
)
(
ethereum
.
Subscription
,
error
)
{
panic
(
"not implemented"
)
}
func
(
m
*
backendMock
)
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
return
m
.
transactionReceipt
(
ctx
,
txHash
)
}
type
transactionServiceMock
struct
{
send
func
(
ctx
context
.
Context
,
request
*
chequebook
.
TxRequest
)
(
txHash
common
.
Hash
,
err
error
)
waitForReceipt
func
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
receipt
*
types
.
Receipt
,
err
error
)
}
func
(
m
*
transactionServiceMock
)
Send
(
ctx
context
.
Context
,
request
*
chequebook
.
TxRequest
)
(
txHash
common
.
Hash
,
err
error
)
{
return
m
.
send
(
ctx
,
request
)
}
func
(
m
*
transactionServiceMock
)
WaitForReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
receipt
*
types
.
Receipt
,
err
error
)
{
return
m
.
waitForReceipt
(
ctx
,
txHash
)
}
type
simpleSwapFactoryBindingMock
struct
{
erc20Address
func
(
*
bind
.
CallOpts
)
(
common
.
Address
,
error
)
deployedContracts
func
(
*
bind
.
CallOpts
,
common
.
Address
)
(
bool
,
error
)
parseSimpleSwapDeployed
func
(
types
.
Log
)
(
*
simpleswapfactory
.
SimpleSwapFactorySimpleSwapDeployed
,
error
)
}
func
(
m
*
simpleSwapFactoryBindingMock
)
ParseSimpleSwapDeployed
(
l
types
.
Log
)
(
*
simpleswapfactory
.
SimpleSwapFactorySimpleSwapDeployed
,
error
)
{
return
m
.
parseSimpleSwapDeployed
(
l
)
}
func
(
m
*
simpleSwapFactoryBindingMock
)
DeployedContracts
(
o
*
bind
.
CallOpts
,
a
common
.
Address
)
(
bool
,
error
)
{
return
m
.
deployedContracts
(
o
,
a
)
}
func
(
m
*
simpleSwapFactoryBindingMock
)
ERC20Address
(
o
*
bind
.
CallOpts
)
(
common
.
Address
,
error
)
{
return
m
.
erc20Address
(
o
)
}
type
simpleSwapBindingMock
struct
{
balance
func
(
*
bind
.
CallOpts
)
(
*
big
.
Int
,
error
)
}
func
(
m
*
simpleSwapBindingMock
)
Balance
(
o
*
bind
.
CallOpts
)
(
*
big
.
Int
,
error
)
{
return
m
.
balance
(
o
)
}
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
)
}
pkg/settlement/swap/chequebook/factory.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook
import
(
"bytes"
"errors"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/sw3-bindings/v2/simpleswapfactory"
"golang.org/x/net/context"
)
var
(
ErrInvalidFactory
=
errors
.
New
(
"not a valid factory contract"
)
ErrNotDeployedByFactory
=
errors
.
New
(
"chequebook not deployed by factory"
)
)
// Factory is the main interface for interacting with the chequebook factory
type
Factory
interface
{
// ERC20Address returns the token for which this factory deploys chequebooks
ERC20Address
(
ctx
context
.
Context
)
(
common
.
Address
,
error
)
// Deploy deploys a new chequebook and returns once confirmed
Deploy
(
ctx
context
.
Context
,
issuer
common
.
Address
,
defaultHardDepositTimeoutDuration
*
big
.
Int
)
(
common
.
Address
,
error
)
// VerifyBytecode checks that the factory is valid
VerifyBytecode
(
ctx
context
.
Context
)
error
// VerifyChequebook checks that the supplied chequebook has been deployed by this factory
VerifyChequebook
(
ctx
context
.
Context
,
chequebook
common
.
Address
)
error
}
type
factory
struct
{
backend
Backend
transactionService
TransactionService
address
common
.
Address
ABI
abi
.
ABI
instance
SimpleSwapFactoryBinding
}
// NewFactory creates a new factory service for the provided factory contract
func
NewFactory
(
backend
Backend
,
transactionService
TransactionService
,
address
common
.
Address
,
simpleSwapFactoryBindingFunc
SimpleSwapFactoryBindingFunc
)
(
Factory
,
error
)
{
ABI
,
err
:=
abi
.
JSON
(
strings
.
NewReader
(
simpleswapfactory
.
SimpleSwapFactoryABI
))
if
err
!=
nil
{
return
nil
,
err
}
instance
,
err
:=
simpleSwapFactoryBindingFunc
(
address
,
backend
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
factory
{
backend
:
backend
,
transactionService
:
transactionService
,
address
:
address
,
ABI
:
ABI
,
instance
:
instance
,
},
nil
}
// Deploy deploys a new chequebook and returns once confirmed
func
(
c
*
factory
)
Deploy
(
ctx
context
.
Context
,
issuer
common
.
Address
,
defaultHardDepositTimeoutDuration
*
big
.
Int
)
(
common
.
Address
,
error
)
{
callData
,
err
:=
c
.
ABI
.
Pack
(
"deploySimpleSwap"
,
issuer
,
big
.
NewInt
(
0
)
.
Set
(
defaultHardDepositTimeoutDuration
))
if
err
!=
nil
{
return
common
.
Address
{},
err
}
request
:=
&
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
.
Address
{},
err
}
receipt
,
err
:=
c
.
transactionService
.
WaitForReceipt
(
ctx
,
txHash
)
if
err
!=
nil
{
return
common
.
Address
{},
err
}
chequebookAddress
,
err
:=
c
.
parseDeployReceipt
(
receipt
)
if
err
!=
nil
{
return
common
.
Address
{},
err
}
return
chequebookAddress
,
nil
}
// parseDeployReceipt parses the address of the deployed chequebook from the receipt
func
(
c
*
factory
)
parseDeployReceipt
(
receipt
*
types
.
Receipt
)
(
address
common
.
Address
,
err
error
)
{
if
receipt
.
Status
!=
1
{
return
common
.
Address
{},
ErrTransactionReverted
}
for
_
,
log
:=
range
receipt
.
Logs
{
if
log
.
Address
!=
c
.
address
{
continue
}
if
event
,
err
:=
c
.
instance
.
ParseSimpleSwapDeployed
(
*
log
);
err
==
nil
{
address
=
event
.
ContractAddress
break
}
}
if
(
address
==
common
.
Address
{})
{
return
common
.
Address
{},
errors
.
New
(
"contract deployment failed"
)
}
return
address
,
nil
}
// VerifyBytecode checks that the factory is valid
func
(
c
*
factory
)
VerifyBytecode
(
ctx
context
.
Context
)
(
err
error
)
{
code
,
err
:=
c
.
backend
.
CodeAt
(
ctx
,
c
.
address
,
nil
)
if
err
!=
nil
{
return
err
}
referenceCode
:=
common
.
FromHex
(
simpleswapfactory
.
SimpleSwapFactoryDeployedCode
)
if
!
bytes
.
Equal
(
code
,
referenceCode
)
{
return
ErrInvalidFactory
}
return
nil
}
// VerifyChequebook checks that the supplied chequebook has been deployed by this factory
func
(
c
*
factory
)
VerifyChequebook
(
ctx
context
.
Context
,
chequebook
common
.
Address
)
error
{
deployed
,
err
:=
c
.
instance
.
DeployedContracts
(
&
bind
.
CallOpts
{
Context
:
ctx
,
},
chequebook
)
if
err
!=
nil
{
return
err
}
if
!
deployed
{
return
ErrNotDeployedByFactory
}
return
nil
}
// ERC20Address returns the token for which this factory deploys chequebooks
func
(
c
*
factory
)
ERC20Address
(
ctx
context
.
Context
)
(
common
.
Address
,
error
)
{
erc20Address
,
err
:=
c
.
instance
.
ERC20Address
(
&
bind
.
CallOpts
{
Context
:
ctx
,
})
if
err
!=
nil
{
return
common
.
Address
{},
err
}
return
erc20Address
,
nil
}
pkg/settlement/swap/chequebook/factory_test.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook_test
import
(
"bytes"
"context"
"errors"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
"github.com/ethersphere/sw3-bindings/v2/simpleswapfactory"
)
func
newTestFactory
(
t
*
testing
.
T
,
factoryAddress
common
.
Address
,
backend
chequebook
.
Backend
,
transactionService
chequebook
.
TransactionService
,
simpleSwapFactoryBinding
chequebook
.
SimpleSwapFactoryBinding
)
(
chequebook
.
Factory
,
error
)
{
return
chequebook
.
NewFactory
(
backend
,
transactionService
,
factoryAddress
,
func
(
addr
common
.
Address
,
b
bind
.
ContractBackend
)
(
chequebook
.
SimpleSwapFactoryBinding
,
error
)
{
if
addr
!=
factoryAddress
{
t
.
Fatalf
(
"initialised binding with wrong address. wanted %x, got %x"
,
factoryAddress
,
addr
)
}
if
b
!=
backend
{
t
.
Fatal
(
"initialised binding with wrong backend"
)
}
return
simpleSwapFactoryBinding
,
nil
})
}
func
TestFactoryERC20Address
(
t
*
testing
.
T
)
{
factoryAddress
:=
common
.
HexToAddress
(
"0xabcd"
)
erc20Address
:=
common
.
HexToAddress
(
"0xeffff"
)
factory
,
err
:=
newTestFactory
(
t
,
factoryAddress
,
&
backendMock
{},
&
transactionServiceMock
{},
&
simpleSwapFactoryBindingMock
{
erc20Address
:
func
(
*
bind
.
CallOpts
)
(
common
.
Address
,
error
)
{
return
erc20Address
,
nil
},
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
addr
,
err
:=
factory
.
ERC20Address
(
context
.
Background
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
addr
!=
erc20Address
{
t
.
Fatalf
(
"wrong erc20Address. wanted %x, got %x"
,
erc20Address
,
addr
)
}
}
func
TestFactoryVerifySelf
(
t
*
testing
.
T
)
{
factoryAddress
:=
common
.
HexToAddress
(
"0xabcd"
)
factory
,
err
:=
newTestFactory
(
t
,
factoryAddress
,
&
backendMock
{
codeAt
:
func
(
ctx
context
.
Context
,
contract
common
.
Address
,
blockNumber
*
big
.
Int
)
([]
byte
,
error
)
{
if
contract
!=
factoryAddress
{
t
.
Fatalf
(
"called with wrong address. wanted %x, got %x"
,
factoryAddress
,
contract
)
}
if
blockNumber
!=
nil
{
t
.
Fatal
(
"not called for latest block"
)
}
return
common
.
FromHex
(
simpleswapfactory
.
SimpleSwapFactoryDeployedCode
),
nil
},
},
&
transactionServiceMock
{},
&
simpleSwapFactoryBindingMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
factory
.
VerifyBytecode
(
context
.
Background
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
func
TestFactoryVerifySelfInvalidCode
(
t
*
testing
.
T
)
{
factoryAddress
:=
common
.
HexToAddress
(
"0xabcd"
)
factory
,
err
:=
newTestFactory
(
t
,
factoryAddress
,
&
backendMock
{
codeAt
:
func
(
ctx
context
.
Context
,
contract
common
.
Address
,
blockNumber
*
big
.
Int
)
([]
byte
,
error
)
{
if
contract
!=
factoryAddress
{
t
.
Fatalf
(
"called with wrong address. wanted %x, got %x"
,
factoryAddress
,
contract
)
}
if
blockNumber
!=
nil
{
t
.
Fatal
(
"not called for latest block"
)
}
return
common
.
FromHex
(
simpleswapfactory
.
AddressBin
),
nil
},
},
&
transactionServiceMock
{},
&
simpleSwapFactoryBindingMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
factory
.
VerifyBytecode
(
context
.
Background
())
if
err
==
nil
{
t
.
Fatal
(
"verified invalid factory"
)
}
if
!
errors
.
Is
(
err
,
chequebook
.
ErrInvalidFactory
)
{
t
.
Fatalf
(
"wrong error. wanted %v, got %v"
,
chequebook
.
ErrInvalidFactory
,
err
)
}
}
func
TestFactoryVerifyChequebook
(
t
*
testing
.
T
)
{
factoryAddress
:=
common
.
HexToAddress
(
"0xabcd"
)
chequebookAddress
:=
common
.
HexToAddress
(
"0xefff"
)
factory
,
err
:=
newTestFactory
(
t
,
factoryAddress
,
&
backendMock
{},
&
transactionServiceMock
{},
&
simpleSwapFactoryBindingMock
{
deployedContracts
:
func
(
o
*
bind
.
CallOpts
,
address
common
.
Address
)
(
bool
,
error
)
{
if
address
!=
chequebookAddress
{
t
.
Fatalf
(
"checked for wrong contract. wanted %v, got %v"
,
chequebookAddress
,
address
)
}
return
true
,
nil
},
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
factory
.
VerifyChequebook
(
context
.
Background
(),
chequebookAddress
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
func
TestFactoryVerifyChequebookInvalid
(
t
*
testing
.
T
)
{
factoryAddress
:=
common
.
HexToAddress
(
"0xabcd"
)
chequebookAddress
:=
common
.
HexToAddress
(
"0xefff"
)
factory
,
err
:=
newTestFactory
(
t
,
factoryAddress
,
&
backendMock
{},
&
transactionServiceMock
{},
&
simpleSwapFactoryBindingMock
{
deployedContracts
:
func
(
o
*
bind
.
CallOpts
,
address
common
.
Address
)
(
bool
,
error
)
{
if
address
!=
chequebookAddress
{
t
.
Fatalf
(
"checked for wrong contract. wanted %v, got %v"
,
chequebookAddress
,
address
)
}
return
false
,
nil
},
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
factory
.
VerifyChequebook
(
context
.
Background
(),
chequebookAddress
)
if
err
==
nil
{
t
.
Fatal
(
"verified invalid chequebook"
)
}
if
!
errors
.
Is
(
err
,
chequebook
.
ErrNotDeployedByFactory
)
{
t
.
Fatalf
(
"wrong error. wanted %v, got %v"
,
chequebook
.
ErrNotDeployedByFactory
,
err
)
}
}
func
TestFactoryDeploy
(
t
*
testing
.
T
)
{
factoryAddress
:=
common
.
HexToAddress
(
"0xabcd"
)
issuerAddress
:=
common
.
HexToAddress
(
"0xefff"
)
defaultTimeout
:=
big
.
NewInt
(
1
)
deployTransactionHash
:=
common
.
HexToHash
(
"0xffff"
)
deployAddress
:=
common
.
HexToAddress
(
"0xdddd"
)
logData
:=
common
.
Hex2Bytes
(
"0xcccc"
)
factory
,
err
:=
newTestFactory
(
t
,
factoryAddress
,
&
backendMock
{},
&
transactionServiceMock
{
send
:
func
(
ctx
context
.
Context
,
request
*
chequebook
.
TxRequest
)
(
txHash
common
.
Hash
,
err
error
)
{
if
request
.
To
!=
factoryAddress
{
t
.
Fatalf
(
"sending to wrong address. wanted %x, got %x"
,
factoryAddress
,
request
.
To
)
}
if
request
.
Value
.
Cmp
(
big
.
NewInt
(
0
))
!=
0
{
t
.
Fatal
(
"trying to send ether"
)
}
return
deployTransactionHash
,
nil
},
waitForReceipt
:
func
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
receipt
*
types
.
Receipt
,
err
error
)
{
if
txHash
!=
deployTransactionHash
{
t
.
Fatalf
(
"waiting for wrong transaction. wanted %x, got %x"
,
deployTransactionHash
,
txHash
)
}
return
&
types
.
Receipt
{
Status
:
1
,
Logs
:
[]
*
types
.
Log
{
{
Data
:
logData
,
},
{
Address
:
factoryAddress
,
Data
:
logData
,
},
},
},
nil
},
},
&
simpleSwapFactoryBindingMock
{
parseSimpleSwapDeployed
:
func
(
log
types
.
Log
)
(
*
simpleswapfactory
.
SimpleSwapFactorySimpleSwapDeployed
,
error
)
{
if
!
bytes
.
Equal
(
log
.
Data
,
logData
)
{
t
.
Fatal
(
"trying to parse wrong log"
)
}
return
&
simpleswapfactory
.
SimpleSwapFactorySimpleSwapDeployed
{
ContractAddress
:
deployAddress
,
},
nil
},
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
chequebookAddress
,
err
:=
factory
.
Deploy
(
context
.
Background
(),
issuerAddress
,
defaultTimeout
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
chequebookAddress
!=
deployAddress
{
t
.
Fatalf
(
"returning wrong address. wanted %x, got %x"
,
deployAddress
,
chequebookAddress
)
}
}
func
TestFactoryDeployReverted
(
t
*
testing
.
T
)
{
factoryAddress
:=
common
.
HexToAddress
(
"0xabcd"
)
issuerAddress
:=
common
.
HexToAddress
(
"0xefff"
)
defaultTimeout
:=
big
.
NewInt
(
1
)
deployTransactionHash
:=
common
.
HexToHash
(
"0xffff"
)
factory
,
err
:=
newTestFactory
(
t
,
factoryAddress
,
&
backendMock
{},
&
transactionServiceMock
{
send
:
func
(
ctx
context
.
Context
,
request
*
chequebook
.
TxRequest
)
(
txHash
common
.
Hash
,
err
error
)
{
if
request
.
To
!=
factoryAddress
{
t
.
Fatalf
(
"sending to wrong address. wanted %x, got %x"
,
factoryAddress
,
request
.
To
)
}
if
request
.
Value
.
Cmp
(
big
.
NewInt
(
0
))
!=
0
{
t
.
Fatal
(
"trying to send ether"
)
}
return
deployTransactionHash
,
nil
},
waitForReceipt
:
func
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
receipt
*
types
.
Receipt
,
err
error
)
{
if
txHash
!=
deployTransactionHash
{
t
.
Fatalf
(
"waiting for wrong transaction. wanted %x, got %x"
,
deployTransactionHash
,
txHash
)
}
return
&
types
.
Receipt
{
Status
:
0
,
},
nil
},
},
&
simpleSwapFactoryBindingMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
err
=
factory
.
Deploy
(
context
.
Background
(),
issuerAddress
,
defaultTimeout
)
if
err
==
nil
{
t
.
Fatal
(
"returned failed chequebook deployment"
)
}
if
!
errors
.
Is
(
err
,
chequebook
.
ErrTransactionReverted
)
{
t
.
Fatalf
(
"wrong error. wanted %v, got %v"
,
chequebook
.
ErrTransactionReverted
,
err
)
}
}
pkg/settlement/swap/chequebook/init.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook
import
(
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/logging"
"github.com/ethersphere/bee/pkg/storage"
)
const
chequebookKey
=
"chequebook"
// Init initialises the chequebook service
func
Init
(
ctx
context
.
Context
,
chequebookFactory
Factory
,
stateStore
storage
.
StateStorer
,
logger
logging
.
Logger
,
swapInitialDeposit
uint64
,
transactionService
TransactionService
,
swapBackend
Backend
,
overlayEthAddress
common
.
Address
,
simpleSwapBindingFunc
SimpleSwapBindingFunc
,
erc20BindingFunc
ERC20BindingFunc
)
(
chequebookService
Service
,
err
error
)
{
// verify that the supplied factory is valid
err
=
chequebookFactory
.
VerifyBytecode
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
erc20Address
,
err
:=
chequebookFactory
.
ERC20Address
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
var
chequebookAddress
common
.
Address
err
=
stateStore
.
Get
(
chequebookKey
,
&
chequebookAddress
)
if
err
!=
nil
{
if
err
!=
storage
.
ErrNotFound
{
return
nil
,
err
}
// if we don't yet have a chequebook, deploy a new one
logger
.
Info
(
"deploying new chequebook"
)
chequebookAddress
,
err
=
chequebookFactory
.
Deploy
(
ctx
,
overlayEthAddress
,
big
.
NewInt
(
0
))
if
err
!=
nil
{
return
nil
,
err
}
logger
.
Infof
(
"deployed chequebook at address %x"
,
chequebookAddress
)
// save the address for later use
err
=
stateStore
.
Put
(
chequebookKey
,
chequebookAddress
)
if
err
!=
nil
{
return
nil
,
err
}
chequebookService
,
err
=
New
(
swapBackend
,
transactionService
,
chequebookAddress
,
erc20Address
,
overlayEthAddress
,
simpleSwapBindingFunc
,
erc20BindingFunc
)
if
err
!=
nil
{
return
nil
,
err
}
if
swapInitialDeposit
!=
0
{
logger
.
Info
(
"depositing into new chequebook"
)
depositHash
,
err
:=
chequebookService
.
Deposit
(
ctx
,
big
.
NewInt
(
int64
(
swapInitialDeposit
)))
if
err
!=
nil
{
return
nil
,
err
}
err
=
chequebookService
.
WaitForDeposit
(
ctx
,
depositHash
)
if
err
!=
nil
{
return
nil
,
err
}
logger
.
Infof
(
"deposited to chequebook %x in transaction %x"
,
chequebookAddress
,
depositHash
)
}
}
else
{
chequebookService
,
err
=
New
(
swapBackend
,
transactionService
,
chequebookAddress
,
erc20Address
,
overlayEthAddress
,
simpleSwapBindingFunc
,
erc20BindingFunc
)
if
err
!=
nil
{
return
nil
,
err
}
logger
.
Infof
(
"using existing chequebook %x"
,
chequebookAddress
)
}
// regardless of how the chequebook service was initialised make sure that the chequebook is valid
err
=
chequebookFactory
.
VerifyChequebook
(
ctx
,
chequebookService
.
Address
())
if
err
!=
nil
{
return
nil
,
err
}
return
chequebookService
,
nil
}
pkg/settlement/swap/chequebook/transaction.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook
import
(
"errors"
"math/big"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/crypto"
"github.com/ethersphere/bee/pkg/logging"
"golang.org/x/net/context"
)
var
(
ErrTransactionReverted
=
errors
.
New
(
"transaction reverted"
)
)
// Backend is the minimum of blockchain backend functions we need
type
Backend
interface
{
bind
.
ContractBackend
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
}
// TxRequest describes a request for a transaction that can be executed
type
TxRequest
struct
{
To
common
.
Address
// recipient of the transaction
Data
[]
byte
// transaction data
GasPrice
*
big
.
Int
// gas price or nil if suggested gas price should be used
GasLimit
uint64
// gas limit or 0 if it should be estimated
Value
*
big
.
Int
// amount of wei to send
}
// TransactionService is the service to send transactions. It takes care of gas price, gas limit and nonce management.
type
TransactionService
interface
{
// Send creates a transaction based on the request and sends it
Send
(
ctx
context
.
Context
,
request
*
TxRequest
)
(
txHash
common
.
Hash
,
err
error
)
// WaitForReceipt waits until either the transaction with the given hash has been mined or the context is cancelled
WaitForReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
receipt
*
types
.
Receipt
,
err
error
)
}
type
transactionService
struct
{
logger
logging
.
Logger
backend
Backend
signer
crypto
.
Signer
sender
common
.
Address
}
// NewTransactionService creates a new transaction service
func
NewTransactionService
(
logger
logging
.
Logger
,
backend
Backend
,
signer
crypto
.
Signer
)
(
TransactionService
,
error
)
{
senderAddress
,
err
:=
signer
.
EthereumAddress
()
if
err
!=
nil
{
return
nil
,
err
}
return
&
transactionService
{
logger
:
logger
,
backend
:
backend
,
signer
:
signer
,
sender
:
senderAddress
,
},
nil
}
// Send creates and signs a transaction based on the request and sends it
func
(
t
*
transactionService
)
Send
(
ctx
context
.
Context
,
request
*
TxRequest
)
(
txHash
common
.
Hash
,
err
error
)
{
tx
,
err
:=
prepareTransaction
(
ctx
,
request
,
t
.
sender
,
t
.
backend
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
signedTx
,
err
:=
t
.
signer
.
SignTx
(
tx
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
err
=
t
.
backend
.
SendTransaction
(
ctx
,
signedTx
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
return
signedTx
.
Hash
(),
nil
}
// WaitForReceipt waits until either the transaction with the given hash has been mined or the context is cancelled
func
(
t
*
transactionService
)
WaitForReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
receipt
*
types
.
Receipt
,
err
error
)
{
for
{
receipt
,
err
:=
t
.
backend
.
TransactionReceipt
(
ctx
,
txHash
)
if
receipt
!=
nil
{
return
receipt
,
nil
}
if
err
!=
nil
{
// some node implementations return an error if the transaction is not yet mined
t
.
logger
.
Tracef
(
"waiting for transaction %x to be mined: %v"
,
txHash
,
err
)
}
else
{
t
.
logger
.
Tracef
(
"waiting for transaction %x to be mined"
,
txHash
)
}
select
{
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
case
<-
time
.
After
(
1
*
time
.
Second
)
:
}
}
}
// prepareTransaction creates a signable transaction based on a request
func
prepareTransaction
(
ctx
context
.
Context
,
request
*
TxRequest
,
from
common
.
Address
,
backend
Backend
)
(
tx
*
types
.
Transaction
,
err
error
)
{
var
gasLimit
uint64
if
request
.
GasLimit
==
0
{
gasLimit
,
err
=
backend
.
EstimateGas
(
ctx
,
ethereum
.
CallMsg
{
From
:
from
,
To
:
&
request
.
To
,
Data
:
request
.
Data
,
})
if
err
!=
nil
{
return
nil
,
err
}
}
else
{
gasLimit
=
request
.
GasLimit
}
var
gasPrice
*
big
.
Int
if
request
.
GasPrice
==
nil
{
gasPrice
,
err
=
backend
.
SuggestGasPrice
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
}
else
{
gasPrice
=
request
.
GasPrice
}
nonce
,
err
:=
backend
.
PendingNonceAt
(
ctx
,
from
)
if
err
!=
nil
{
return
nil
,
err
}
return
types
.
NewTransaction
(
nonce
,
request
.
To
,
request
.
Value
,
gasLimit
,
gasPrice
,
request
.
Data
,
),
nil
}
pkg/settlement/swap/chequebook/transaction_test.go
0 → 100644
View file @
b3bc0460
// Copyright 2020 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
chequebook_test
import
(
"bytes"
"context"
"crypto/ecdsa"
"io/ioutil"
"math/big"
"testing"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/logging"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
)
type
signerMock
struct
{
signTx
func
(
transaction
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
}
func
(
*
signerMock
)
EthereumAddress
()
(
common
.
Address
,
error
)
{
return
common
.
Address
{},
nil
}
func
(
*
signerMock
)
Sign
(
data
[]
byte
)
([]
byte
,
error
)
{
return
nil
,
nil
}
func
(
m
*
signerMock
)
SignTx
(
transaction
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
m
.
signTx
(
transaction
)
}
func
(
*
signerMock
)
PublicKey
()
(
*
ecdsa
.
PublicKey
,
error
)
{
return
nil
,
nil
}
func
TestTransactionSend
(
t
*
testing
.
T
)
{
logger
:=
logging
.
New
(
ioutil
.
Discard
,
0
)
recipient
:=
common
.
HexToAddress
(
"0xabcd"
)
signedTx
:=
types
.
NewTransaction
(
0
,
recipient
,
big
.
NewInt
(
0
),
0
,
nil
,
nil
)
txData
:=
common
.
Hex2Bytes
(
"0xabcdee"
)
value
:=
big
.
NewInt
(
1
)
suggestedGasPrice
:=
big
.
NewInt
(
2
)
estimatedGasLimit
:=
uint64
(
3
)
nonce
:=
uint64
(
2
)
request
:=
&
chequebook
.
TxRequest
{
To
:
recipient
,
Data
:
txData
,
Value
:
value
,
}
transactionService
,
err
:=
chequebook
.
NewTransactionService
(
logger
,
&
backendMock
{
sendTransaction
:
func
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
{
if
tx
!=
signedTx
{
t
.
Fatal
(
"not sending signed transaction"
)
}
return
nil
},
estimateGas
:
func
(
ctx
context
.
Context
,
call
ethereum
.
CallMsg
)
(
gas
uint64
,
err
error
)
{
if
!
bytes
.
Equal
(
call
.
To
.
Bytes
(),
recipient
.
Bytes
())
{
t
.
Fatalf
(
"estimating with wrong recipient. wanted %x, got %x"
,
recipient
,
call
.
To
)
}
if
!
bytes
.
Equal
(
call
.
Data
,
txData
)
{
t
.
Fatal
(
"estimating with wrong data"
)
}
return
estimatedGasLimit
,
nil
},
suggestGasPrice
:
func
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
{
return
suggestedGasPrice
,
nil
},
pendingNonceAt
:
func
(
ctx
context
.
Context
,
account
common
.
Address
)
(
uint64
,
error
)
{
return
nonce
,
nil
},
},
&
signerMock
{
signTx
:
func
(
transaction
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
if
!
bytes
.
Equal
(
transaction
.
To
()
.
Bytes
(),
recipient
.
Bytes
())
{
t
.
Fatalf
(
"signing transaction with wrong recipient. wanted %x, got %x"
,
recipient
,
transaction
.
To
())
}
if
!
bytes
.
Equal
(
transaction
.
Data
(),
txData
)
{
t
.
Fatalf
(
"signing transaction with wrong data. wanted %x, got %x"
,
txData
,
transaction
.
Data
())
}
if
transaction
.
Value
()
.
Cmp
(
value
)
!=
0
{
t
.
Fatalf
(
"signing transaction with wrong value. wanted %d, got %d"
,
value
,
transaction
.
Value
())
}
if
transaction
.
Gas
()
!=
estimatedGasLimit
{
t
.
Fatalf
(
"signing transaction with wrong gas. wanted %d, got %d"
,
estimatedGasLimit
,
transaction
.
Gas
())
}
if
transaction
.
GasPrice
()
.
Cmp
(
suggestedGasPrice
)
!=
0
{
t
.
Fatalf
(
"signing transaction with wrong gasprice. wanted %d, got %d"
,
suggestedGasPrice
,
transaction
.
GasPrice
())
}
if
transaction
.
Nonce
()
!=
nonce
{
t
.
Fatalf
(
"signing transaction with wrong nonce. wanted %d, got %d"
,
nonce
,
transaction
.
Nonce
())
}
return
signedTx
,
nil
},
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
txHash
,
err
:=
transactionService
.
Send
(
context
.
Background
(),
request
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
txHash
.
Bytes
(),
signedTx
.
Hash
()
.
Bytes
())
{
t
.
Fatal
(
"returning wrong transaction hash"
)
}
}
func
TestTransactionWaitForReceipt
(
t
*
testing
.
T
)
{
logger
:=
logging
.
New
(
ioutil
.
Discard
,
0
)
txHash
:=
common
.
HexToHash
(
"0xabcdee"
)
transactionService
,
err
:=
chequebook
.
NewTransactionService
(
logger
,
&
backendMock
{
transactionReceipt
:
func
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
return
&
types
.
Receipt
{
TxHash
:
txHash
,
},
nil
},
},
&
signerMock
{})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
receipt
,
err
:=
transactionService
.
WaitForReceipt
(
context
.
Background
(),
txHash
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
receipt
.
TxHash
!=
txHash
{
t
.
Fatal
(
"got wrong receipt"
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment