Skip to content

Commit

Permalink
Merge pull request #23 from ravi0131/payment-channel-ckb
Browse files Browse the repository at this point in the history
Payment channel ckb
  • Loading branch information
tinnendo authored Oct 23, 2024
2 parents 91e65f9 + 74c3499 commit c60eb98
Show file tree
Hide file tree
Showing 84 changed files with 17,526 additions and 1 deletion.
28 changes: 28 additions & 0 deletions payment-channel-ckb/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# log files
*.log

perun-ckb-demo

# Dependency directories (remove the comment below to include it)
# vendor/
devnet/accounts
devnet/data
devnet/specs
devnet/ckb-miner.toml
devnet/ckb.toml
devnet/default.db-options
devnet/system_scripts
.vscode/
3 changes: 3 additions & 0 deletions payment-channel-ckb/.gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "devnet/contracts"]
path = devnet/contracts
url = [email protected]:perun-network/perun-ckb-contract
89 changes: 89 additions & 0 deletions payment-channel-ckb/client/balances.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package client

import (
"context"
"encoding/binary"
"fmt"
"log"
"math"
"math/big"
"strconv"
"time"

"github.com/nervosnetwork/ckb-sdk-go/v2/indexer"
"github.com/nervosnetwork/ckb-sdk-go/v2/types"
"perun.network/perun-ckb-backend/wallet/address"
)

type BalanceExtractor func(*indexer.LiveCell) *big.Int

func ckbBalanceExtractor(cell *indexer.LiveCell) *big.Int {
return new(big.Int).SetUint64(cell.Output.Capacity)
}

func sudtBalanceExtractor(cell *indexer.LiveCell) *big.Int {
if len(cell.OutputData) != 16 {
return big.NewInt(0)
}
return new(big.Int).SetUint64(binary.LittleEndian.Uint64(cell.OutputData))
}

func (p *PaymentClient) PollBalances() {
defer log.Println("PollBalances: stopped")
pollingInterval := time.Second
searchKey := &indexer.SearchKey{
Script: address.AsParticipant(p.Account.Address()).PaymentScript,
ScriptType: types.ScriptTypeLock,
ScriptSearchMode: types.ScriptSearchModeExact,
Filter: nil,
WithData: true,
}
log.Println("PollBalances")
updateBalance := func() {
ctx, _ := context.WithTimeout(context.Background(), pollingInterval)

cells, err := p.rpcClient.GetCells(ctx, searchKey, indexer.SearchOrderDesc, math.MaxUint32, "")
if err != nil {
log.Println("balance poll error: ", err)
return
}
ckbBalance := big.NewInt(0)
sudtBalance := big.NewInt(0)
for _, cell := range cells.Objects {
ckbBalance = new(big.Int).Add(ckbBalance, ckbBalanceExtractor(cell))
sudtBalance = new(big.Int).Add(sudtBalance, sudtBalanceExtractor(cell))
}

p.balanceMutex.Lock()
if ckbBalance.Cmp(p.balance) != 0 || sudtBalance.Cmp(p.sudtBalance) != 0 {
// Update ckb balance.
p.balance = ckbBalance
//ckbBal := p.balance.Int64()

// Update sudt balance.
p.sudtBalance = sudtBalance

p.balanceMutex.Unlock()
//p.NotifyAllBalance(ckbBal) // TODO: Update demo tui to allow for big.Int balances
} else {
p.balanceMutex.Unlock()
}
}
updateBalance()
//return "CKbytes: " + p.balance.String() + ", SUDT: " + p.sudtBalance.String()
/*
// Poll the balance every 5 seconds.
for {
updateBalance()
time.Sleep(pollingInterval)
}
*/
}

func FormatBalance(ckbBal, sudtBal *big.Int) string {
log.Printf("balances: ckb = %s || sudt = %s", ckbBal.String(), sudtBal.String())
balCKByte, _ := ShannonToCKByte(ckbBal).Float64()
return fmt.Sprintf("[green]%s\t[yellow]%s[white]",
strconv.FormatFloat(balCKByte, 'f', 2, 64)+" CKByte",
fmt.Sprintf("%v", sudtBal.Int64())+" SUDT")
}
91 changes: 91 additions & 0 deletions payment-channel-ckb/client/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package client

import (
"context"
"fmt"
"math/big"

"perun.network/go-perun/channel"
"perun.network/go-perun/client"
)

type PaymentChannel struct {
ch *client.Channel
assets []channel.Asset
}

// newPaymentChannel creates a new payment channel.
func newPaymentChannel(ch *client.Channel, assets []channel.Asset) *PaymentChannel {
return &PaymentChannel{
ch: ch,
assets: assets,
}
}

func (c PaymentChannel) State() *channel.State {
return c.ch.State().Clone()
}

func (c PaymentChannel) SendPayment(amounts map[channel.Asset]float64) {
// Transfer the given amount from us to peer.
// Use UpdateBy to update the channel state.
err := c.ch.Update(context.TODO(), func(state *channel.State) {
actor := c.ch.Idx()
peer := 1 - actor
//fmt.Println("Send payment handler called")
for a, amount := range amounts {
fmt.Println(a)
fmt.Println(amount)
if amount < 0 {
continue
}
/*
switch a := a.(type) {
case *asset.Asset:
if a.IsCKBytes {
fmt.Println("inside condition isCKBytes")
shannonAmount := CKByteToShannon(big.NewFloat(amount))
state.Allocation.TransferBalance(actor, peer, a, shannonAmount)
} else {
fmt.Println("inside if conditional !isCKBytes")
intAmount := new(big.Int).SetUint64(uint64(amount))
state.Allocation.TransferBalance(actor, peer, a, intAmount)
}
}
*/

shannonAmount := CKByteToShannon(big.NewFloat(amount))
state.Allocation.TransferBalance(actor, peer, a, shannonAmount)

}

})
if err != nil {
panic(err)
}
if err != nil {
panic(err) // We panic on error to keep the code simple.
}
}

// Settle settles the payment channel and withdraws the funds.
func (c PaymentChannel) Settle() {
// Finalize the channel to enable fast settlement.
if !c.ch.State().IsFinal {
err := c.ch.Update(context.TODO(), func(state *channel.State) {
state.IsFinal = true
})
if err != nil {
panic(err)
}
}

// Settle concludes the channel and withdraws the funds.
err := c.ch.Settle(context.TODO())
if err != nil {
panic(err)
}

// Close frees up channel resources.
c.ch.Close()
}
Loading

0 comments on commit c60eb98

Please sign in to comment.