Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow single withdrawer in CC swaps #22

Open
wants to merge 4 commits into
base: remove-channelID-array
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 28 additions & 3 deletions channel/adjudicator.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 PolyCrypt GmbH
// Copyright 2025 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -19,9 +19,11 @@ import (
"errors"
"fmt"
"github.com/stellar/go/xdr"
"math/big"
pchannel "perun.network/go-perun/channel"
"perun.network/go-perun/log"
pwallet "perun.network/go-perun/wallet"
"perun.network/perun-stellar-backend/channel/types"
"perun.network/perun-stellar-backend/client"
"perun.network/perun-stellar-backend/wallet"
"time"
Expand Down Expand Up @@ -89,6 +91,12 @@ func (a *Adjudicator) Withdraw(ctx context.Context, req pchannel.AdjudicatorReq,
}
if req.Tx.State.IsFinal {
log.Println("Channel is final, closing now")
withdrawSelf := needWithdraw([]pchannel.Bal{req.Tx.State.Balances[0][req.Idx], req.Tx.State.Balances[1][req.Idx]}, req.Tx.State.Assets)
withdrawOther := needWithdraw([]pchannel.Bal{req.Tx.State.Balances[0][1-req.Idx], req.Tx.State.Balances[1][1-req.Idx]}, req.Tx.State.Assets)
if req.Idx == 0 && a.oneWithdrawer && (!withdrawSelf || !withdrawOther) { // If one participant does not need to withdraw, the swap is cross-chain which means A does not need to close
log.Println("A only closes when A & B have to withdraw")
return nil
}
err := a.Close(ctx, req.Tx.State, req.Tx.Sigs)
if err != nil {
chanControl, errChanState = a.CB.GetChannelInfo(ctx, a.perunAddr, req.Tx.State.ID)
Expand Down Expand Up @@ -119,12 +127,19 @@ func (a *Adjudicator) Withdraw(ctx context.Context, req pchannel.AdjudicatorReq,
}

func (a *Adjudicator) handleWithdrawal(ctx context.Context, req pchannel.AdjudicatorReq) error {
if a.oneWithdrawer {
withdrawOther := needWithdraw([]pchannel.Bal{req.Tx.State.Balances[0][1-req.Idx], req.Tx.State.Balances[1][1-req.Idx]}, req.Tx.State.Assets)
if a.oneWithdrawer && withdrawOther {
log.Println("Withdrawing other", req.Idx)
if err := a.withdrawOther(ctx, req); err != nil {
return err
}
}
return a.withdraw(ctx, req)
withdrawSelf := needWithdraw([]pchannel.Bal{req.Tx.State.Balances[0][req.Idx], req.Tx.State.Balances[1][req.Idx]}, req.Tx.State.Assets)
if withdrawSelf {
log.Println("Withdrawing self", req.Idx)
return a.withdraw(ctx, req)
}
return nil
}

func (a *Adjudicator) withdraw(ctx context.Context, req pchannel.AdjudicatorReq) error {
Expand Down Expand Up @@ -173,3 +188,13 @@ func (a Adjudicator) Progress(ctx context.Context, req pchannel.ProgressReq) err
// only relevant for AppChannels
return nil
}

func needWithdraw(balances []pchannel.Bal, assets []pchannel.Asset) bool {
for i, bal := range balances {
_, ok := assets[i].(*types.StellarAsset)
if bal.Cmp(big.NewInt(0)) != 0 && ok { // if balance is 0 or asset is not stellar asset, participant does not need to withdraw
return true
}
}
return false
}
2 changes: 1 addition & 1 deletion channel/ethbackend.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func assetToEthAsset(asset channel.Asset) ChannelAsset {
log.Panicf("expected asset of type MultiLedgerAsset, but got wrong asset type: %T", asset)
}
id := new(big.Int)
_, ok = id.SetString(string(multiAsset.AssetID().LedgerID().MapKey()), 10) // base 10 for decimal numbers
_, ok = id.SetString(string(multiAsset.LedgerBackendID().LedgerID().MapKey()), 10) // base 10 for decimal numbers
if !ok {
log.Panicf("Error: Failed to parse string into big.Int")
}
Expand Down
10 changes: 5 additions & 5 deletions channel/funder.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 PolyCrypt GmbH
// Copyright 2025 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -106,7 +106,7 @@ func (f *Funder) fundParty(ctx context.Context, req pchannel.FundingReq) error {
}

if req.Idx == pchannel.Index(0) && !chanState.Control.FundedA {
shouldFund := need_funding(req.State.Balances[0], req.State.Assets)
shouldFund := needFunding(req.State.Balances[0], req.State.Assets)
if !shouldFund {
log.Println("Party A does not need to fund")
return nil
Expand Down Expand Up @@ -148,9 +148,9 @@ func (f *Funder) fundParty(ctx context.Context, req pchannel.FundingReq) error {
log.Println("Balance A: ", bal0, bal1, " after funding amount: ", req.State.Balances, req.State.Assets)
continue
}
if req.Idx == pchannel.Index(1) && !chanState.Control.FundedB && (chanState.Control.FundedA || !need_funding(req.State.Balances[0], req.State.Assets)) { // If party A has funded or does not need to fund, party B funds
if req.Idx == pchannel.Index(1) && !chanState.Control.FundedB && (chanState.Control.FundedA || !needFunding(req.State.Balances[0], req.State.Assets)) { // If party A has funded or does not need to fund, party B funds
log.Println("Funding party B")
shouldFund := need_funding(req.State.Balances[1], req.State.Assets)
shouldFund := needFunding(req.State.Balances[1], req.State.Assets)
if !shouldFund {
log.Println("Party B does not need to fund", req.State.Balances[1], req.State.Assets)
return nil
Expand Down Expand Up @@ -269,7 +269,7 @@ func assetSliceToSet(assets []xdr.ScVal) map[string]struct{} {
return assetSet
}

func need_funding(balances []pchannel.Bal, assets []pchannel.Asset) bool {
func needFunding(balances []pchannel.Bal, assets []pchannel.Asset) bool {
for i, bal := range balances {
_, ok := assets[i].(*types.StellarAsset)
if bal.Cmp(big.NewInt(0)) != 0 && ok { // if balance is 0 or asset is not stellar asset, participant does not need to fund
Expand Down
6 changes: 1 addition & 5 deletions channel/test/setup.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 PolyCrypt GmbH
// Copyright 2025 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -114,8 +114,6 @@ func NewTestSetup(t *testing.T, options ...bool) *Setup {
}

_, kpsToFund, _ := MakeRandPerunAccsWallets(5)
// kpsToFund[2], _ = keypair.ParseFull("SD4XPDWFDY25V7NRMF47QE4WT6WOFWUJIZGFRMMCRHGVINJ3RMMDG6WS")
// kpsToFund[3], _ = keypair.ParseFull("SDHDGJMVERIXSN5LQ5KDLW3F2QIVM2D6CLP3BDHSKWBAYX53YDEY3FND")
require.NoError(t, CreateFundStellarAccounts(kpsToFund, initLumensBalance))

depTokenOneKp := kpsToFund[2]
Expand All @@ -142,8 +140,6 @@ func NewTestSetup(t *testing.T, options ...bool) *Setup {
require.NoError(t, InitTokenContract(depTokenOneKp, tokenAddressOne, HorizonURL))
require.NoError(t, InitTokenContract(depTokenTwoKp, tokenAddressTwo, HorizonURL))

// acc0 := wallet.NewAccount("5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", *kpsToFund[0].FromAddress(), [20]byte([]byte{86, 253, 40, 156, 238, 113, 74, 94, 71, 28, 65, 132, 54, 239, 166, 62, 120, 13, 122, 135}))
// acc1 := wallet.NewAccount("7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", *kpsToFund[0].FromAddress(), [20]byte([]byte{101, 54, 66, 91, 233, 90, 102, 97, 246, 198, 246, 141, 112, 155, 107, 225, 82, 120, 93, 246}))
acc0, err := wallet.NewRandomAccountWithAddress(mathrand.New(mathrand.NewSource(0)), kpsToFund[0].FromAddress())
acc1, err := wallet.NewRandomAccountWithAddress(mathrand.New(mathrand.NewSource(0)), kpsToFund[1].FromAddress())
w0 := wallet.NewEphemeralWallet()
Expand Down
4 changes: 2 additions & 2 deletions channel/types/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ func (a Asset) Address() []byte {

}

// AssetID returns the asset ID of the Stellar asset.
func (s StellarAsset) AssetID() multi.AssetID {
// LedgerBackendID returns the asset ID of the Stellar asset.
func (s StellarAsset) LedgerBackendID() multi.LedgerBackendID {
return s.id
}

Expand Down
24 changes: 12 additions & 12 deletions channel/types/ethasset.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ func (id ChainID) MapKey() multi.LedgerIDMapKey {
type (
// Asset is an Ethereum asset.
EthAsset struct {
assetID AssetID
assetID LedgerBackendID
AssetHolder wallet.Address
}

AssetID struct {
// LedherBackendID holds the ChainID and BackendID of an Asset.
LedgerBackendID struct {
backendID uint32
ledgerID ChainID
}
Expand All @@ -137,23 +137,23 @@ type (
)

func MakeEthAsset(id *big.Int, holder wallet.Address) EthAsset {
return EthAsset{assetID: AssetID{backendID: 1, ledgerID: MakeChainID(id)}, AssetHolder: holder}
return EthAsset{assetID: LedgerBackendID{backendID: 1, ledgerID: MakeChainID(id)}, AssetHolder: holder}
}

func (id AssetID) BackendID() uint32 {
func (id LedgerBackendID) BackendID() uint32 {
return id.backendID
}

func (id AssetID) LedgerID() multi.LedgerID {
func (id LedgerBackendID) LedgerID() multi.LedgerID {
return &id.ledgerID
}

// MakeAssetID makes a AssetID for the given id.
func MakeAssetID(id *big.Int) multi.AssetID {
// MakeAssetID makes a LedgerBackendID for the given id.
func MakeLedgerBackendID(id *big.Int) multi.LedgerBackendID {
if id.Sign() < 0 {
panic("must not be smaller than zero")
}
return AssetID{backendID: 1, ledgerID: MakeChainID(id)}
return LedgerBackendID{backendID: 1, ledgerID: MakeChainID(id)}
}

// MapKey returns the asset's map key representation.
Expand Down Expand Up @@ -184,11 +184,11 @@ func (a *EthAsset) UnmarshalBinary(data []byte) error {

// LedgerID returns the ledger ID the asset lives on.
func (a EthAsset) LedgerID() multi.LedgerID {
return a.AssetID().LedgerID()
return a.LedgerBackendID().LedgerID()
}

// AssetID returns the ledger ID the asset lives on.
func (a EthAsset) AssetID() multi.AssetID {
// LedgerBackendID returns the ledger ID the asset lives on.
func (a EthAsset) LedgerBackendID() multi.LedgerBackendID {
return a.assetID
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require (
github.com/ethereum/go-ethereum v1.10.12
github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2
github.com/stretchr/testify v1.9.0
perun.network/go-perun v0.12.1-0.20250114072911-f46b0c55fe65
perun.network/go-perun v0.12.1-0.20250128081648-21d0af4e234b
polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,8 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
perun.network/go-perun v0.12.1-0.20250114072911-f46b0c55fe65 h1:kJ3AS374fe23a/9puoaOwCr9Bx2L/WJ5p2npDql3m4A=
perun.network/go-perun v0.12.1-0.20250114072911-f46b0c55fe65/go.mod h1:uH8iwi75alXDizxxDzH0A+6uqXPbagCpKfl8ECMv/cA=
perun.network/go-perun v0.12.1-0.20250128081648-21d0af4e234b h1:6FeodthJZB10aWGk/DgtV2VicacyUnLaUoT8OUcwSms=
perun.network/go-perun v0.12.1-0.20250128081648-21d0af4e234b/go.mod h1:uH8iwi75alXDizxxDzH0A+6uqXPbagCpKfl8ECMv/cA=
polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37 h1:iA5GzEa/hHfVlQpimEjPV09NATwHXxSjWNB0VVodtew=
polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37/go.mod h1:XUBrNtqgEhN3EEOP/5gh7IBd3xVHKidCjXDZfl9+kMU=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
Expand Down
Binary file modified testdata/perun_soroban_contract.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion wire/balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ func extractAndConvertLedgerID(asset channel.Asset) (uint64, error) {
if !ok {
return 0, errors.New("invalid Asset format")
}
id := multiAsset.AssetID().LedgerID()
id := multiAsset.LedgerBackendID().LedgerID()
if id == nil {
return 0, errors.New("invalid LedgerID")
}
Expand Down