Skip to content

Commit

Permalink
Merge pull request #18 from perun-network/feat-multiasset
Browse files Browse the repository at this point in the history
Feature: Multiasset Support
  • Loading branch information
iljabvh authored Jul 18, 2024
2 parents 94a49dd + 61837f2 commit 71880f4
Show file tree
Hide file tree
Showing 26 changed files with 517 additions and 224 deletions.
26 changes: 17 additions & 9 deletions channel/adjudicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,20 @@ type Adjudicator struct {
log log.Embedding
CB *client.ContractBackend
acc *wallet.Account
assetAddr xdr.ScAddress
assetAddrs xdr.ScVec //xdr.ScAddress
perunAddr xdr.ScAddress
maxIters int
pollingInterval time.Duration
}

// NewAdjudicator returns a new Adjudicator.
func NewAdjudicator(acc *wallet.Account, cb *client.ContractBackend, perunID xdr.ScAddress, assetID xdr.ScAddress) *Adjudicator {
func NewAdjudicator(acc *wallet.Account, cb *client.ContractBackend, perunID xdr.ScAddress, assetIDs xdr.ScVec) *Adjudicator {
return &Adjudicator{
challengeDuration: &DefaultChallengeDuration,
CB: cb,
acc: acc,
perunAddr: perunID,
assetAddr: assetID,
assetAddrs: assetIDs,
maxIters: MaxIterationsUntilAbort,
pollingInterval: DefaultPollingInterval,
log: log.MakeEmbedding(log.Default()),
Expand All @@ -60,20 +60,26 @@ func (a *Adjudicator) GetPerunAddr() xdr.ScAddress {
return a.perunAddr
}

func (a *Adjudicator) GetAssetAddr() xdr.ScAddress {
return a.assetAddr
func (a *Adjudicator) GetAssetAddrs() []xdr.ScAddress {
var addrs []xdr.ScAddress
for _, addrScVal := range a.assetAddrs {
addr := addrScVal.MustAddress()
addrs = append(addrs, addr)
}

return addrs
}

func (a *Adjudicator) Subscribe(ctx context.Context, cid pchannel.ID) (pchannel.AdjudicatorSubscription, error) {
perunAddr := a.GetPerunAddr()
assetAddr := a.GetAssetAddr()
return NewAdjudicatorSub(ctx, cid, a.CB, perunAddr, assetAddr, a.challengeDuration)
assetAddrs := a.GetAssetAddrs()
return NewAdjudicatorSub(ctx, cid, a.CB, perunAddr, assetAddrs, a.challengeDuration)
}

func (a *Adjudicator) Withdraw(ctx context.Context, req pchannel.AdjudicatorReq, smap pchannel.StateMap) error {

if req.Tx.State.IsFinal {
log.Println("Withdraw called")
log.Println("Withdraw called by Adjudicator")

if err := a.Close(ctx, req.Tx.State, req.Tx.Sigs); err != nil {
chanControl, errChanState := a.CB.GetChannelInfo(ctx, a.perunAddr, req.Tx.State.ID)
Expand Down Expand Up @@ -108,13 +114,15 @@ func (a *Adjudicator) Withdraw(ctx context.Context, req pchannel.AdjudicatorReq,
}

func (a *Adjudicator) withdraw(ctx context.Context, req pchannel.AdjudicatorReq) error {
log.Println("withdraw called by Adjudicator")

perunAddress := a.GetPerunAddr()
return a.CB.Withdraw(ctx, perunAddress, req)
}

func (a *Adjudicator) Close(ctx context.Context, state *pchannel.State, sigs []pwallet.Sig) error {

log.Println("Close called")
log.Println("Close called by Adjudicator")
perunAddr := a.GetPerunAddr()

return a.CB.Close(ctx, perunAddr, state, sigs)
Expand Down
6 changes: 3 additions & 3 deletions channel/adjudicator_sub.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type AdjEventSub struct {
chanControl wire.Control
cid pchannel.ID
perunAddr xdr.ScAddress
assetAddr xdr.ScAddress
assetAddrs []xdr.ScAddress
events chan event.PerunEvent
subErrors chan error
err error
Expand All @@ -48,15 +48,15 @@ type AdjEventSub struct {
log log.Embedding
}

func NewAdjudicatorSub(ctx context.Context, cid pchannel.ID, cb *client.ContractBackend, perunAddr xdr.ScAddress, assetAddr xdr.ScAddress, challengeDuration *time.Duration) (pchannel.AdjudicatorSubscription, error) {
func NewAdjudicatorSub(ctx context.Context, cid pchannel.ID, cb *client.ContractBackend, perunAddr xdr.ScAddress, assetAddrs []xdr.ScAddress, challengeDuration *time.Duration) (pchannel.AdjudicatorSubscription, error) {

sub := &AdjEventSub{
challengeDuration: challengeDuration,
cb: cb,
chanControl: wire.Control{},
cid: cid,
perunAddr: perunAddr,
assetAddr: assetAddr,
assetAddrs: assetAddrs,
events: make(chan event.PerunEvent, DefaultBufferSize),
subErrors: make(chan error, 1),
pollInterval: DefaultSubscriptionPollingInterval,
Expand Down
7 changes: 0 additions & 7 deletions channel/adjudicator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ func TestHappyChannel(t *testing.T) {
adjBob := setup.GetAdjudicators()[1]

ctxAliceWithdraw := setup.NewCtx(chtest.DefaultTestTimeout)
ctxBobWithdraw := setup.NewCtx(chtest.DefaultTestTimeout)

adjState := perunState
next := adjState.Clone()
Expand Down Expand Up @@ -91,12 +90,6 @@ func TestHappyChannel(t *testing.T) {

require.NoError(t, err)
require.NoError(t, adjBob.Withdraw(ctx, reqBob, nil))
perunAddrBob := adjBob.GetPerunAddr()
stellarChanBob, err := adjBob.CB.GetChannelInfo(ctxBobWithdraw, perunAddrBob, next.ID)

require.NoError(t, err)

require.True(t, stellarChanBob.Control.WithdrawnB)

}

Expand Down
2 changes: 1 addition & 1 deletion channel/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"os"
)

const PerunContractPath = "../testdata/perun_soroban_contract.wasm"
const PerunContractPath = "../testdata/perun_soroban_multi_contract.wasm"

func AssembleInstallContractCodeOp(sourceAccount string, wasmFileName string) *txnbuild.InvokeHostFunction {
// Assemble the InvokeHostFunction UploadContractWasm operation:
Expand Down
19 changes: 12 additions & 7 deletions channel/funder.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ const DefaultPollingInterval = time.Duration(6) * time.Second
type Funder struct {
cb *client.ContractBackend
perunAddr xdr.ScAddress
assetAddr xdr.ScAddress
assetAddrs xdr.ScVec
maxIters int
pollingInterval time.Duration
}

func NewFunder(acc *wallet.Account, contractBackend *client.ContractBackend, perunAddr xdr.ScAddress, assetAddr xdr.ScAddress) *Funder {
func NewFunder(acc *wallet.Account, contractBackend *client.ContractBackend, perunAddr xdr.ScAddress, assetAddrs xdr.ScVec) *Funder {
return &Funder{
cb: contractBackend,
perunAddr: perunAddr,
assetAddr: assetAddr,
assetAddrs: assetAddrs,
maxIters: MaxIterationsUntilAbort,
pollingInterval: DefaultPollingInterval,
}
Expand All @@ -51,8 +51,13 @@ func (f *Funder) GetPerunAddr() xdr.ScAddress {
return f.perunAddr
}

func (f *Funder) GetAssetAddr() xdr.ScAddress {
return f.assetAddr
func (f *Funder) GetAssetAddrs() []xdr.ScAddress {
var addrs []xdr.ScAddress
for _, addrScVal := range f.assetAddrs {
addr := addrScVal.MustAddress()
addrs = append(addrs, addr)
}
return addrs
}

func (f *Funder) Fund(ctx context.Context, req pchannel.FundingReq) error {
Expand Down Expand Up @@ -136,11 +141,11 @@ func (f *Funder) FundChannel(ctx context.Context, state *pchannel.State, funderI
return errors.New("error while making balances")
}

if !balsStellar.Token.Equals(f.assetAddr) {
if !balsStellar.Tokens.Equals(&f.assetAddrs) {
return errors.New("asset address is not equal to the address stored in the state")
}

return f.cb.Fund(ctx, f.perunAddr, f.assetAddr, state.ID, funderIdx)
return f.cb.Fund(ctx, f.perunAddr, state.ID, funderIdx)
}

func (f *Funder) AbortChannel(ctx context.Context, state *pchannel.State) error {
Expand Down
4 changes: 2 additions & 2 deletions channel/funder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ func TestFunding_Happy(t *testing.T) {

func TestFunding_TimeoutNotFunded(t *testing.T) {
setup := chtest.NewTestSetup(t)
stellarAsset := setup.GetTokenAsset()
stellarAssets := setup.GetTokenAsset()
accs := setup.GetAccounts()
addrAlice := accs[0].Address()
addrBob := accs[1].Address()
addrList := []pwallet.Address{addrAlice, addrBob}
perunParams, perunState := chtest.NewParamsWithAddressStateWithAsset(t, addrList, stellarAsset)
perunParams, perunState := chtest.NewParamsWithAddressStateWithAsset(t, addrList, stellarAssets)
freqAlice := pchannel.NewFundingReq(perunParams, perunState, 0, perunState.Balances)
freqBob := pchannel.NewFundingReq(perunParams, perunState, 1, perunState.Balances)
freqs := []*pchannel.FundingReq{freqAlice, freqBob}
Expand Down
100 changes: 62 additions & 38 deletions channel/test/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,30 @@ import (
"perun.network/perun-stellar-backend/channel/types"
"perun.network/perun-stellar-backend/client"
"perun.network/perun-stellar-backend/wallet"
"perun.network/perun-stellar-backend/wire/scval"
pkgtest "polycry.pt/poly-go/test"
"runtime"
"testing"
"time"
)

const (
PerunContractPath = "testdata/perun_soroban_contract.wasm"
PerunContractPath = "testdata/perun_soroban_multi_contract.wasm"
StellarAssetContractPath = "testdata/perun_soroban_token.wasm"
initLumensBalance = "10000000"
initTokenBalance = uint64(2000000)
DefaultTestTimeout = 30
)

type Setup struct {
t *testing.T
accs []*wallet.Account
ws []*wallet.EphemeralWallet
cbs []*client.ContractBackend
Rng *mathrand.Rand
funders []*channel.Funder
adjs []*channel.Adjudicator
assetID pchannel.Asset
t *testing.T
accs []*wallet.Account
ws []*wallet.EphemeralWallet
cbs []*client.ContractBackend
Rng *mathrand.Rand
funders []*channel.Funder
adjs []*channel.Adjudicator
assetIDs []pchannel.Asset
}

func (s *Setup) GetStellarClients() []*client.ContractBackend {
Expand All @@ -71,8 +72,8 @@ func (s *Setup) GetAdjudicators() []*channel.Adjudicator {
return s.adjs
}

func (s *Setup) GetTokenAsset() pchannel.Asset {
return s.assetID
func (s *Setup) GetTokenAsset() []pchannel.Asset {
return s.assetIDs
}

func (s *Setup) GetAccounts() []*wallet.Account {
Expand Down Expand Up @@ -103,26 +104,40 @@ func getDataFilePath(filename string) (string, error) {

func NewTestSetup(t *testing.T) *Setup {

accs, kpsToFund, ws := MakeRandPerunAccsWallets(4)
accs, kpsToFund, ws := MakeRandPerunAccsWallets(5)
require.NoError(t, CreateFundStellarAccounts(kpsToFund, initLumensBalance))

depTokenKp := kpsToFund[2]
depPerunKp := kpsToFund[3]
depTokenOneKp := kpsToFund[2]
depTokenTwoKp := kpsToFund[3]

depTokenKps := []*keypair.Full{depTokenOneKp, depTokenTwoKp}

depPerunKp := kpsToFund[4]

relPathPerun, err := getDataFilePath(PerunContractPath)
require.NoError(t, err)
relPathAsset, err := getDataFilePath(StellarAssetContractPath)
require.NoError(t, err)

tokenAddress, _ := Deploy(t, depTokenKp, relPathAsset)
perunAddress, _ := Deploy(t, depPerunKp, relPathPerun)

require.NoError(t, InitTokenContract(depTokenKp, tokenAddress))
tokenAddressOne, _ := Deploy(t, depTokenOneKp, relPathAsset)
tokenAddressTwo, _ := Deploy(t, depTokenTwoKp, relPathAsset)

SetupAccountsAndContracts(t, depTokenKp, kpsToFund[:2], tokenAddress, initTokenBalance)
tokenAddresses := []xdr.ScAddress{tokenAddressOne, tokenAddressTwo}

assetContractID, err := types.NewStellarAssetFromScAddress(tokenAddress)
require.NoError(t, err)
require.NoError(t, InitTokenContract(depTokenOneKp, tokenAddressOne))
require.NoError(t, InitTokenContract(depTokenTwoKp, tokenAddressTwo))

SetupAccountsAndContracts(t, depTokenKps, kpsToFund[:2], tokenAddresses, initTokenBalance)

var assetContractIDs []pchannel.Asset

for _, tokenAddress := range tokenAddresses {
assetContractID, err := types.NewStellarAssetFromScAddress(tokenAddress)
require.NoError(t, err)
assetContractIDs = append(assetContractIDs, assetContractID)
}

cbs := NewContractBackendsFromKeys(kpsToFund[:2])

Expand All @@ -136,34 +151,43 @@ func NewTestSetup(t *testing.T) *Setup {
channelCBs := []*client.ContractBackend{aliceCB, bobCB}
channelWallets := []*wallet.EphemeralWallet{aliceWallet, bobWallet}

funders, adjs := CreateFundersAndAdjudicators(channelAccs, cbs, perunAddress, tokenAddress)
funders, adjs := CreateFundersAndAdjudicators(channelAccs, cbs, perunAddress, tokenAddresses)

setup := Setup{
t: t,
accs: channelAccs,
ws: channelWallets,
cbs: channelCBs,
funders: funders,
adjs: adjs,
assetID: assetContractID,
t: t,
accs: channelAccs,
ws: channelWallets,
cbs: channelCBs,
funders: funders,
adjs: adjs,
assetIDs: assetContractIDs,
}

return &setup
}

func SetupAccountsAndContracts(t *testing.T, deployerKp *keypair.Full, kps []*keypair.Full, tokenAddress xdr.ScAddress, tokenBalance uint64) {
for _, kp := range kps {
addr, err := types.MakeAccountAddress(kp)
require.NoError(t, err)
require.NoError(t, MintToken(deployerKp, tokenAddress, tokenBalance, addr))
func SetupAccountsAndContracts(t *testing.T, deployerKps []*keypair.Full, kps []*keypair.Full, tokenAddresses []xdr.ScAddress, tokenBalance uint64) {

require.Equal(t, len(deployerKps), len(tokenAddresses))

for i, _ := range deployerKps {
for _, kp := range kps {
addr, err := types.MakeAccountAddress(kp)
require.NoError(t, err)
require.NoError(t, MintToken(deployerKps[i], tokenAddresses[i], tokenBalance, addr))

}
}
}
func CreateFundersAndAdjudicators(accs []*wallet.Account, cbs []*client.ContractBackend, perunAddress, tokenAddress xdr.ScAddress) ([]*channel.Funder, []*channel.Adjudicator) {
func CreateFundersAndAdjudicators(accs []*wallet.Account, cbs []*client.ContractBackend, perunAddress xdr.ScAddress, tokenScAddresses []xdr.ScAddress) ([]*channel.Funder, []*channel.Adjudicator) {
funders := make([]*channel.Funder, len(accs))
adjs := make([]*channel.Adjudicator, len(accs))

tokenVecAddresses := scval.MakeScVecFromScAddresses(tokenScAddresses)

for i, acc := range accs {
funders[i] = channel.NewFunder(acc, cbs[i], perunAddress, tokenAddress)
adjs[i] = channel.NewAdjudicator(acc, cbs[i], perunAddress, tokenAddress)
funders[i] = channel.NewFunder(acc, cbs[i], perunAddress, tokenVecAddresses)
adjs[i] = channel.NewAdjudicator(acc, cbs[i], perunAddress, tokenVecAddresses)
}
return funders, adjs
}
Expand Down Expand Up @@ -301,21 +325,21 @@ func CreateFundStellarAccounts(pairs []*keypair.Full, initialBalance string) err
return nil
}

func NewParamsWithAddressStateWithAsset(t *testing.T, partsAddr []pwallet.Address, asset pchannel.Asset) (*pchannel.Params, *pchannel.State) {
func NewParamsWithAddressStateWithAsset(t *testing.T, partsAddr []pwallet.Address, assets []pchannel.Asset) (*pchannel.Params, *pchannel.State) {

rng := pkgtest.Prng(t)

numParts := 2

return ptest.NewRandomParamsAndState(rng, ptest.WithNumLocked(0).Append(
ptest.WithAssets(asset),
ptest.WithAssets(assets...),
ptest.WithNumAssets(len(assets)),
ptest.WithVersion(0),
ptest.WithNumParts(numParts),
ptest.WithParts(partsAddr...),
ptest.WithIsFinal(false),
ptest.WithLedgerChannel(true),
ptest.WithVirtualChannel(false),
ptest.WithNumAssets(1),
ptest.WithoutApp(),
ptest.WithBalancesInRange(big.NewInt(0).Mul(big.NewInt(1), big.NewInt(100_000)), big.NewInt(0).Mul(big.NewInt(1), big.NewInt(100_000))),
))
Expand Down
Loading

0 comments on commit 71880f4

Please sign in to comment.