Skip to content

Commit

Permalink
Merge pull request #24 from perun-network/add-ckb-example
Browse files Browse the repository at this point in the history
Add CKB Payment Channel Example
  • Loading branch information
tinnendo authored Nov 18, 2024
2 parents 9d3d37b + d9c54fa commit a747642
Show file tree
Hide file tree
Showing 91 changed files with 17,907 additions and 1 deletion.
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,41 @@ jobs:
go run .
docker stop ganache
- name: Payment Channel CKB
working-directory: payment-channel-ckb
run: |
sudo apt-get update
sudo apt-get install -y jq sed gawk tmux tmuxp expect make
curl -LO https://github.com/nervosnetwork/ckb/releases/download/v0.109.0/ckb_v0.109.0_x86_64-unknown-linux-gnu.tar.gz
tar -xzf ckb_v0.109.0_x86_64-unknown-linux-gnu.tar.gz
sudo cp ckb_v0.109.0_x86_64-unknown-linux-gnu/ckb /usr/local/bin/
curl -LO https://github.com/nervosnetwork/ckb-cli/releases/download/v1.4.0/ckb-cli_v1.4.0_x86_64-unknown-linux-gnu.tar.gz
tar -xzf ckb-cli_v1.4.0_x86_64-unknown-linux-gnu.tar.gz
sudo cp ckb-cli_v1.4.0_x86_64-unknown-linux-gnu/ckb-cli /usr/local/bin/
curl -LO https://github.com/nervosnetwork/capsule/releases/download/v0.9.2/capsule_v0.9.2_x86_64-linux.tar.gz
tar -xzf capsule_v0.9.2_x86_64-linux.tar.gz
sudo cp capsule_v0.9.2_x86_64-linux/capsule /usr/local/bin/
cd ./devnet
chmod +x setup-devnet.sh print_accounts.sh deploy_contracts.sh sudt_helper.sh
./setup-devnet.sh
ckb run > /dev/null 2>&1 &
sleep 3
ckb miner > /dev/null 2>&1 &
sleep 3
./print_accounts.sh
sleep 6
expect fund_accounts.expect
sleep 10
./deploy_contracts.sh
sleep 15
./sudt_helper.sh fund
sleep 10
./sudt_helper.sh balances
sleep 30
cd ..
go run main.go
- name: Payment Channel ETH
working-directory: payment-channel
env:
Expand Down
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
91 changes: 91 additions & 0 deletions payment-channel-ckb/client/balances.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2024 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

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() {
pollingInterval := time.Second
searchKey := &indexer.SearchKey{
Script: address.AsParticipant(p.Account.Address()).PaymentScript,
ScriptType: types.ScriptTypeLock,
ScriptSearchMode: types.ScriptSearchModeExact,
Filter: nil,
WithData: true,
}
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

// Update sudt balance.
p.sudtBalance = sudtBalance

p.balanceMutex.Unlock()
} else {
p.balanceMutex.Unlock()
}
}
updateBalance()

}

func FormatBalance(ckbBal, sudtBal *big.Int) 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")
}
86 changes: 86 additions & 0 deletions payment-channel-ckb/client/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2024 PolyCrypt GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package client

import (
"context"
"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
for a, amount := range amounts {

if amount < 0 {
continue
}

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

}

})
if err != nil {
panic(err)
}

}

// 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 a747642

Please sign in to comment.