Skip to content
This repository was archived by the owner on Aug 2, 2021. It is now read-only.

Swap available balance #1892

Merged
merged 20 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f0431f4
swap: introduce paidOut variable and update this variable upon sendin…
Eknir Oct 18, 2019
de5b152
swap: make tests pass again
Eknir Oct 18, 2019
18500a9
swap, contract/swap: create event iterators on Deposit and Withdraw a…
Eknir Oct 18, 2019
d11b4b3
swap: add availableBalance to swapAPI
Eknir Oct 18, 2019
d4e5abc
contracts/swap: add Withdraw and Deposit methods
Eknir Oct 18, 2019
1ff69ff
contracts/swap: add Deposit and Withdraw to Contract interface
Eknir Oct 18, 2019
6eb0a57
swap: added draft for TestAvailableBalance (not working yet)
Eknir Oct 18, 2019
523d220
swap: compute available balance upon startup and update the value on …
Eknir Oct 21, 2019
075c322
swap: finish TestAvailableBalance
Eknir Oct 21, 2019
7807019
swap: review mortelli
Eknir Oct 21, 2019
e0cab6a
contracts/swap: check error before returning
Eknir Oct 21, 2019
203dbec
swap: small improvements
Eknir Oct 22, 2019
f52e515
swap, contracts/swap: compute availableBalance without event watchers
Eknir Oct 23, 2019
57416dd
Merge branch 'master' into swap-available-balance
Eknir Oct 23, 2019
4011ffe
swap: fix TestAvailableBalance
Eknir Oct 23, 2019
80296ac
contracts/swap: add amount as a parameter to deposit
Eknir Oct 24, 2019
cacb39f
contracts/swap: don't allow auth.value in Deposit
Eknir Oct 28, 2019
ed886ab
Merge branch 'master' into swap-available-balance
Eknir Oct 28, 2019
5bc0c28
contracts/swap: comment LiquidBalance function
Eknir Oct 29, 2019
c11f840
Merge branch 'master' into swap-available-balance
Eknir Oct 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions contracts/swap/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ type Backend interface {

// Contract interface defines the methods exported from the underlying go-bindings for the smart contract
type Contract interface {
// Withdraw attempts to withdraw Wei from the chequebook
Withdraw(auth *bind.TransactOpts, backend Backend, amount *big.Int) (*types.Receipt, error)
// Deposit sends a raw transaction to the chequebook, triggering the fallback—depositing amount
Deposit(auth *bind.TransactOpts, backend Backend) (*types.Receipt, error)
// CashChequeBeneficiary cashes the cheque by the beneficiary
CashChequeBeneficiary(auth *bind.TransactOpts, backend Backend, beneficiary common.Address, cumulativePayout *big.Int, ownerSig []byte) (*CashChequeResult, *types.Receipt, error)
// ContractParams returns contract info (e.g. deployed address)
Expand All @@ -55,6 +59,10 @@ type Contract interface {
Issuer(opts *bind.CallOpts) (common.Address, error)
// PaidOut returns the total paid out amount for the given address
PaidOut(opts *bind.CallOpts, addr common.Address) (*big.Int, error)
//TotalDeposit returns the total amount in Wei ever deposited in the chequebook
TotalDeposit() (*big.Int, error)
//TotalWithdrawn returns the total amount in Wei ever withdrawn from the chequebook
TotalWithdrawn() (*big.Int, error)
}

// CashChequeResult summarizes the result of a CashCheque or CashChequeBeneficiary call
Expand Down Expand Up @@ -99,6 +107,25 @@ func InstanceAt(address common.Address, backend Backend) (Contract, error) {
return c, err
}

// Withdraw withdraws amount from the chequebook and blocks until the transaction is mined
func (s simpleContract) Withdraw(auth *bind.TransactOpts, backend Backend, amount *big.Int) (*types.Receipt, error) {
tx, err := s.instance.Withdraw(auth, amount)
if err != nil {
return nil, err
}
return WaitFunc(auth, backend, tx)
}

// Deposit sends a transaction to the chequebook, which deposits the amount set in Auth.Value and blocks until the transaction is mined
func (s simpleContract) Deposit(auth *bind.TransactOpts, backend Backend) (*types.Receipt, error) {
rawSimpleSwap := contract.SimpleSwapRaw{Contract: s.instance}
tx, err := rawSimpleSwap.Transfer(auth)
if err != nil {
return nil, err
}
return WaitFunc(auth, backend, tx)
}

// CashChequeBeneficiary cashes the cheque on the blockchain and blocks until the transaction is mined.
func (s simpleContract) CashChequeBeneficiary(auth *bind.TransactOpts, backend Backend, beneficiary common.Address, cumulativePayout *big.Int, ownerSig []byte) (*CashChequeResult, *types.Receipt, error) {
tx, err := s.instance.CashChequeBeneficiary(auth, beneficiary, cumulativePayout, ownerSig)
Expand Down Expand Up @@ -152,6 +179,41 @@ func (s simpleContract) PaidOut(opts *bind.CallOpts, addr common.Address) (*big.
return s.instance.PaidOut(opts, addr)
}

// TotalDeposit iterates over all Deposit events and returns the total amount ever deposited
func (s simpleContract) TotalDeposit() (totalDeposit *big.Int, err error) {
totalDeposit = big.NewInt(0)
depositIterator, err := s.instance.FilterDeposit(nil)
if err != nil {
return nil, err
}

for depositIterator.Next() {
totalDeposit = totalDeposit.Add(totalDeposit, depositIterator.Event.Amount)
}
if depositIterator.Error() != nil {
return nil, depositIterator.Error()
}
return totalDeposit, nil
}

// TotalWithdrawn iterates over all Withdraw events and returns the total amount ever withdrawn
func (s simpleContract) TotalWithdrawn() (totalWithdrawn *big.Int, err error) {
totalWithdrawn = big.NewInt(0)
withdrawIterator, err := s.instance.FilterWithdraw(nil)
if err != nil {
return nil, err
}

for withdrawIterator.Next() {
totalWithdrawn = totalWithdrawn.Add(totalWithdrawn, withdrawIterator.Event.Amount)
}
if withdrawIterator.Error() != nil {
return nil, withdrawIterator.Error()
}

return totalWithdrawn, withdrawIterator.Error()
}

// ValidateCode checks that the on-chain code at address matches the expected swap
// contract code.
func ValidateCode(ctx context.Context, b bind.ContractBackend, address common.Address) error {
Expand Down
2 changes: 2 additions & 0 deletions swap/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ func (p *Peer) sendCheque() error {
return err
}

p.swap.updateAvailableBalance(int64(p.getLastSentCumulativePayout() - cheque.CumulativePayout))

p.logger.Info("sending cheque to peer", "honey", cheque.Honey, "cumulativePayout", cheque.ChequeParams.CumulativePayout, "beneficiary", cheque.Beneficiary, "contract", cheque.Contract)
return p.Send(context.Background(), &EmitChequeMsg{
Cheque: cheque,
Expand Down
1 change: 1 addition & 0 deletions swap/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ type swapAPI interface {
SentCheques() (map[enode.ID]*Cheque, error)
ReceivedCheque(peer enode.ID) (cheque *Cheque, err error)
ReceivedCheques() (map[enode.ID]*Cheque, error)
AvailableBalance() uint64
}

// API would be the API accessor for protocol methods
Expand Down
8 changes: 4 additions & 4 deletions swap/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestHandshake(t *testing.T) {
defer clean()

ctx := context.Background()
err = testDeploy(ctx, swap)
err = testDeploy(ctx, swap, 0)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -133,11 +133,11 @@ func TestEmitCheque(t *testing.T) {
ctx := context.Background()

log.Debug("deploy to simulated backend")
err := testDeploy(ctx, creditorSwap)
err := testDeploy(ctx, creditorSwap, 0)
if err != nil {
t.Fatal(err)
}
err = testDeploy(ctx, debitorSwap)
err = testDeploy(ctx, debitorSwap, 0)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -222,7 +222,7 @@ func TestTriggerPaymentThreshold(t *testing.T) {
defer clean()

ctx := context.Background()
err := testDeploy(ctx, debitorSwap)
err := testDeploy(ctx, debitorSwap, 0)
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion swap/simulations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func newSimServiceMap(params *swapSimulationParams) map[string]simulation.Servic
ts.spec.Hook = protocols.NewAccounting(balance)
ts.swap = balance
// deploy the accounting to the `SimulatedBackend`
err = testDeploy(context.Background(), balance)
err = testDeploy(context.Background(), balance, 0)
if err != nil {
return nil, nil, err
}
Expand Down
49 changes: 46 additions & 3 deletions swap/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethersphere/swarm/contracts/swap"
contract "github.com/ethersphere/swarm/contracts/swap"
"github.com/ethersphere/swarm/p2p/protocols"
"github.com/ethersphere/swarm/state"
Expand All @@ -60,7 +59,8 @@ type Swap struct {
backend contract.Backend // the backend (blockchain) used
owner *Owner // contract access
params *Params // economic and operational parameters
contract swap.Contract // reference to the smart contract
contract contract.Contract // reference to the smart contract
availableBalance uint64 // amount in Wei against which new cheques can be safely written
honeyPriceOracle HoneyOracle // oracle which resolves the price of honey (in Wei)
}

Expand Down Expand Up @@ -178,6 +178,7 @@ func New(dbPath string, prvkey *ecdsa.PrivateKey, backendURL string, params *Par
return nil, err
}
swapLog.Info("Using backend network ID", "ID", chainID.Uint64())

// create the owner of SWAP
owner := createOwner(prvkey)
// create the swap instance
Expand All @@ -191,6 +192,13 @@ func New(dbPath string, prvkey *ecdsa.PrivateKey, backendURL string, params *Par
if swap.contract, err = swap.StartChequebook(chequebookAddressFlag, initialDepositAmountFlag); err != nil {
return nil, err
}

// set the available balance
if swap.availableBalance, err = swap.computeAvailableBalance(); err != nil {
return nil, err
}
swapLog.Info("availabale balance", "balance", swap.availableBalance)

return swap, nil
}

Expand Down Expand Up @@ -344,6 +352,35 @@ func (s *Swap) handleEmitChequeMsg(ctx context.Context, p *Peer, msg *EmitCheque
return err
}

func (s *Swap) computeAvailableBalance() (uint64, error) {
// get the total amount (Wei) ever deposited
deposit, err := s.contract.TotalDeposit()
if err != nil {
return 0, err
}
// get the total amount (Wei) ever withdrawn
withdrawn, err := s.contract.TotalWithdrawn()
if err != nil {
return 0, err
}
// read the total value (Wei) of all cheques cheques sent
var totalPaidOut uint64
sentCheques, err := s.SentCheques()
if err != nil {
return 0, err
}
for _, v := range sentCheques {
totalPaidOut += v.ChequeParams.CumulativePayout
}
fmt.Println(deposit.Uint64(), withdrawn.Uint64(), totalPaidOut, deposit.Uint64()-withdrawn.Uint64()-totalPaidOut)
return deposit.Uint64() - withdrawn.Uint64() - totalPaidOut, nil
}

// updateAvailableBalance updates the available balance amount
func (s *Swap) updateAvailableBalance(amount int64) {
s.availableBalance = uint64(int64(s.availableBalance) + amount)
}

// cashCheque should be called async as it blocks until the transaction(s) are mined
// The function cashes the cheque by sending it to the blockchain
func cashCheque(s *Swap, otherSwap contract.Contract, opts *bind.TransactOpts, cheque *Cheque) {
Expand Down Expand Up @@ -434,6 +471,11 @@ func (s *Swap) Balances() (map[enode.ID]int64, error) {
return balances, nil
}

// AvailableBalance returns the total balance of the chequebook against which new cheques can be written
func (s *Swap) AvailableBalance() uint64 {
return s.availableBalance
}

// SentCheque returns the last sent cheque for a given peer
func (s *Swap) SentCheque(peer enode.ID) (cheque *Cheque, err error) {
if swapPeer := s.getPeer(peer); swapPeer != nil {
Expand Down Expand Up @@ -567,7 +609,7 @@ func (s *Swap) Close() error {
}

// GetParams returns contract parameters (Bin, ABI, contractAddress) from the contract
func (s *Swap) GetParams() *swap.Params {
func (s *Swap) GetParams() *contract.Params {
return s.contract.ContractParams()
}

Expand Down Expand Up @@ -674,6 +716,7 @@ func (s *Swap) deployLoop(opts *bind.TransactOpts, defaultHarddepositTimeoutDura
swapLog.Warn("chequebook deploy error, retrying...", "try", try, "error", err)
continue
}
s.updateAvailableBalance(opts.Value.Int64())
return instance, nil
}
return nil, err
Expand Down
Loading