mirror of
https://github.com/AthanorLabs/atomic-swap.git
synced 2026-01-09 14:18:03 -05:00
update alice/bob protocol
This commit is contained in:
14
README.md
14
README.md
@@ -9,14 +9,19 @@ Start ganache-cli with determinstic keys:
|
||||
ganache-cli -d
|
||||
```
|
||||
|
||||
Start monerod for stagenet:
|
||||
Start monerod for regtest:
|
||||
```
|
||||
monerod --stagenet
|
||||
./monerod --regtest --fixed-difficulty=1 --rpc-bind-port 18081 --offline
|
||||
```
|
||||
|
||||
Start monero-wallet-rpc:
|
||||
Start monero-wallet-rpc for Bob with some wallet that has regtest monero:
|
||||
```
|
||||
./monero-wallet-rpc --stagenet --rpc-bind-port 18082 --password "" --disable-rpc-login --wallet-dir .
|
||||
./monero-wallet-rpc --rpc-bind-port 18083 --password "" --disable-rpc-login --wallet-file test-wallet
|
||||
```
|
||||
|
||||
Start monero-wallet-rpc for Alice:
|
||||
```
|
||||
./monero-wallet-rpc --rpc-bind-port 18084 --password "" --disable-rpc-login --wallet-dir .
|
||||
```
|
||||
|
||||
##### Compiling contract bindings
|
||||
@@ -28,7 +33,6 @@ Set `SOLC_BIN` to the downloaded binary
|
||||
export SOLC_BIN=solc
|
||||
```
|
||||
|
||||
|
||||
Generate the bindings
|
||||
```
|
||||
./scripts/generate-bindings.sh
|
||||
|
||||
@@ -159,31 +159,40 @@ func (a *alice) WatchForClaim() (<-chan *monero.PrivateKeyPair, error) {
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case claim := <-ch:
|
||||
// got Bob's secret
|
||||
sbBytes := claim.S.Bytes()
|
||||
var sb [32]byte
|
||||
copy(sb[:], sbBytes)
|
||||
for {
|
||||
select {
|
||||
case claim := <-ch:
|
||||
fmt.Println("got claim", claim)
|
||||
if claim == nil || claim.S == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
skB, err := monero.NewPrivateSpendKey(sb[:])
|
||||
if err != nil {
|
||||
fmt.Printf("failed to convert Bob's secret into a key: %w", err)
|
||||
// got Bob's secret
|
||||
sbBytes := claim.S.Bytes()
|
||||
var sb [32]byte
|
||||
copy(sb[:], sbBytes)
|
||||
|
||||
skB, err := monero.NewPrivateSpendKey(sb[:])
|
||||
if err != nil {
|
||||
fmt.Printf("failed to convert Bob's secret into a key: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
vkA, err := skB.View()
|
||||
if err != nil {
|
||||
fmt.Printf("failed to get view key from Bob's secret spend key: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
skAB := monero.SumPrivateSpendKeys(skB, a.privkeys.SpendKey())
|
||||
vkAB := monero.SumPrivateViewKeys(vkA, a.privkeys.ViewKey())
|
||||
kpAB := monero.NewPrivateKeyPair(skAB, vkAB)
|
||||
|
||||
out <- kpAB
|
||||
return
|
||||
case <-a.ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
vkA, err := skB.View()
|
||||
if err != nil {
|
||||
fmt.Printf("failed to get view key from Bob's secret spend key: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
skAB := monero.SumPrivateSpendKeys(skB, a.privkeys.SpendKey())
|
||||
vkAB := monero.SumPrivateViewKeys(vkA, a.privkeys.ViewKey())
|
||||
kpAB := monero.NewPrivateKeyPair(skAB, vkAB)
|
||||
out <- kpAB
|
||||
case <-a.ctx.Done():
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -141,12 +141,18 @@ func (b *bob) WatchForReady() (<-chan struct{}, error) {
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ch:
|
||||
// contract is ready!!
|
||||
close(done)
|
||||
case <-b.ctx.Done():
|
||||
return
|
||||
for {
|
||||
select {
|
||||
case event := <-ch:
|
||||
if !event.B {
|
||||
continue
|
||||
}
|
||||
|
||||
// contract is ready!!
|
||||
close(done)
|
||||
case <-b.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -236,6 +242,10 @@ func (b *bob) LockFunds(amount uint) (monero.Address, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := b.client.Refresh(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fmt.Println("Bob: successfully locked funds")
|
||||
fmt.Println("address: ", address)
|
||||
return address, nil
|
||||
@@ -249,6 +259,21 @@ func (b *bob) ClaimFunds() error {
|
||||
// call swap.Swap.Claim() w/ b.privkeys.sk, revealing Bob's secret spend key
|
||||
secret := b.privkeys.Bytes()
|
||||
s := big.NewInt(0).SetBytes(secret)
|
||||
_, err := b.contract.Claim(txOpts, s)
|
||||
return err
|
||||
tx, err := b.contract.Claim(txOpts, s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("success! Bob claimed funds")
|
||||
fmt.Println("tx hash: ", tx.Hash())
|
||||
|
||||
receipt, err := b.ethClient.TransactionReceipt(b.ctx, tx.Hash())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//fmt.Println("tx logs: ", fmt.Sprintf("0x%x", receipt.Logs[0].Data))
|
||||
fmt.Println("included in block number: ", receipt.Logs[0].BlockNumber)
|
||||
//fmt.Println("expected secret: ", fmt.Sprintf("0x%x", secret))
|
||||
return nil
|
||||
}
|
||||
|
||||
52
cmd/alice.go
52
cmd/alice.go
@@ -37,28 +37,6 @@ func (n *node) doProtocolAlice() error {
|
||||
}
|
||||
}
|
||||
|
||||
claim, err := n.alice.WatchForClaim()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
// TODO: add t1 timeout case
|
||||
select {
|
||||
case <-n.done:
|
||||
return nil
|
||||
case kp := <-claim:
|
||||
fmt.Printf("Bob claimed ether! got secret: %v", kp)
|
||||
address, err := n.alice.CreateMoneroWallet(kp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("successfully created monero wallet from our secrets: address=%s", address)
|
||||
// TODO: get and print balance
|
||||
}
|
||||
}
|
||||
|
||||
n.wait()
|
||||
return nil
|
||||
}
|
||||
@@ -113,6 +91,36 @@ func (n *node) handleMessageAlice(who peer.ID, msg net.Message, setupDone chan s
|
||||
|
||||
fmt.Printf("deployed Swap contract: address=%s\n", address)
|
||||
|
||||
claim, err := n.alice.WatchForClaim()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
// TODO: add t1 timeout case
|
||||
select {
|
||||
case <-n.done:
|
||||
fmt.Println("done")
|
||||
return
|
||||
case kp := <-claim:
|
||||
if kp == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("Bob claimed ether! got secret: %v", kp)
|
||||
address, err := n.alice.CreateMoneroWallet(kp)
|
||||
if err != nil {
|
||||
fmt.Println("failed to create monero address: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("successfully created monero wallet from our secrets: address=%s", address)
|
||||
// TODO: get and print balance
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
out := &net.NotifyContractDeployed{
|
||||
Address: address.String(),
|
||||
}
|
||||
|
||||
36
cmd/bob.go
36
cmd/bob.go
@@ -40,34 +40,6 @@ func (n *node) doProtocolBob() error {
|
||||
}
|
||||
}
|
||||
|
||||
// ready, err := n.bob.WatchForReady()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// refund, err := n.bob.WatchForRefund()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// for {
|
||||
// // TODO: add t0 timeout case
|
||||
// select {
|
||||
// case <-n.done:
|
||||
// return nil
|
||||
// case <-ready:
|
||||
// fmt.Println("Alice called Ready!")
|
||||
|
||||
// // contract ready, let's claim our ether
|
||||
// if err := n.bob.ClaimFunds(); err != nil {
|
||||
// return fmt.Errorf("failed to redeem ether: %w", err)
|
||||
// }
|
||||
// case kp := <-refund:
|
||||
// fmt.Println("Alice refunded, got monero account key", kp)
|
||||
// // TODO: generate wallet
|
||||
// }
|
||||
// }
|
||||
|
||||
n.wait()
|
||||
return nil
|
||||
}
|
||||
@@ -140,19 +112,25 @@ func (n *node) handleMessageBob(who peer.ID, msg net.Message, setupDone chan str
|
||||
return
|
||||
case <-ready:
|
||||
fmt.Println("Alice called Ready!")
|
||||
fmt.Println("attempting to claim funds...")
|
||||
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(time.Second * 3)
|
||||
|
||||
// contract ready, let's claim our ether
|
||||
if err := n.bob.ClaimFunds(); err != nil {
|
||||
fmt.Printf("failed to redeem ether: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("funds claimed!!")
|
||||
return
|
||||
case kp := <-refund:
|
||||
if kp == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Println("Alice refunded, got monero account key", kp)
|
||||
return
|
||||
// TODO: generate wallet
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAliceMoneroEndpoint = "http://127.0.0.1:18083/json_rpc"
|
||||
defaultBobMoneroEndpoint = "http://127.0.0.1:18080/json_rpc"
|
||||
defaultAliceMoneroEndpoint = "http://127.0.0.1:18084/json_rpc"
|
||||
defaultBobMoneroEndpoint = "http://127.0.0.1:18083/json_rpc"
|
||||
defaultEthEndpoint = "ws://localhost:8545"
|
||||
defaultPrivKeyAlice = "4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"
|
||||
defaultPrivKeyBob = "6cbed15c793ce57650b9877cf6fa156fbef513c4e6134f022a85b1ffdd59b2a1"
|
||||
|
||||
@@ -9,6 +9,7 @@ type Client interface {
|
||||
GetBalance(idx uint) (*getBalanceResponse, error)
|
||||
Transfer(to Address, accountIdx, amount uint) error
|
||||
GenerateFromKeys(kp *PrivateKeyPair, filename, password string) error
|
||||
Refresh() error
|
||||
}
|
||||
|
||||
type client struct {
|
||||
@@ -44,3 +45,22 @@ func (c *client) GenerateFromKeys(kp *PrivateKeyPair, filename, password string)
|
||||
func (c *client) GetAddress(idx uint) (*getAddressResponse, error) {
|
||||
return c.callGetAddress(idx)
|
||||
}
|
||||
|
||||
func (c *client) Refresh() error {
|
||||
return c.refresh()
|
||||
}
|
||||
|
||||
func (c *client) refresh() error {
|
||||
const method = "refresh"
|
||||
|
||||
resp, err := postRPC(c.endpoint, method, "{}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Error != nil {
|
||||
return resp.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,18 +41,3 @@ func (c *client) callGenerateBlocks(address string, amount uint) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) refresh() error {
|
||||
const method = "refresh"
|
||||
|
||||
resp, err := postRPC(c.endpoint, method, "{}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Error != nil {
|
||||
return resp.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package swap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@@ -18,10 +21,15 @@ const (
|
||||
keyBob = "6cbed15c793ce57650b9877cf6fa156fbef513c4e6134f022a85b1ffdd59b2a1"
|
||||
)
|
||||
|
||||
func setBigIntLE(s []byte) *big.Int {
|
||||
func reverse(s []byte) []byte {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func setBigIntLE(s []byte) *big.Int {
|
||||
s = reverse(s)
|
||||
return big.NewInt(0).SetBytes(s)
|
||||
}
|
||||
|
||||
@@ -67,7 +75,7 @@ func TestSwap_Claim(t *testing.T) {
|
||||
secretBob := keyPairBob.Bytes()
|
||||
|
||||
// setup
|
||||
conn, err := ethclient.Dial("http://127.0.0.1:8545")
|
||||
conn, err := ethclient.Dial("ws://127.0.0.1:8545")
|
||||
require.NoError(t, err)
|
||||
|
||||
pk_a, err := crypto.HexToECDSA(keyAlice)
|
||||
@@ -84,7 +92,7 @@ func TestSwap_Claim(t *testing.T) {
|
||||
copy(pkAliceFixed[:], pubKeyAlice)
|
||||
var pkBobFixed [32]byte
|
||||
copy(pkBobFixed[:], pubKeyBob)
|
||||
_, _, swap, err := DeploySwap(authAlice, conn, pkAliceFixed, pkBobFixed)
|
||||
_, _, swap, err := DeploySwap(authAlice, conn, pkBobFixed, pkAliceFixed)
|
||||
require.NoError(t, err)
|
||||
|
||||
txOpts := &bind.TransactOpts{
|
||||
@@ -97,11 +105,8 @@ func TestSwap_Claim(t *testing.T) {
|
||||
Signer: authBob.Signer,
|
||||
}
|
||||
|
||||
// callOpts := &bind.CallOpts{From: address}
|
||||
|
||||
// Bob tries to claim before Alice has called ready, should fail
|
||||
// _, err = swap.Claim(txOptsBob, setBigIntLE(secretBob))
|
||||
s := big.NewInt(0).SetBytes(secretBob)
|
||||
s := big.NewInt(0).SetBytes(reverse(secretBob))
|
||||
_, err = swap.Claim(txOptsBob, s)
|
||||
require.Errorf(t, err, "'isReady == false' cannot claim yet!")
|
||||
|
||||
@@ -109,13 +114,42 @@ func TestSwap_Claim(t *testing.T) {
|
||||
_, err = swap.SetReady(txOpts)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Bob tries to claim before Alice has called ready, should fail
|
||||
watchForEvent(t, swap)
|
||||
|
||||
_, err = swap.Claim(txOptsBob, s)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(time.Second * 10)
|
||||
|
||||
// TODO check whether Bob's account balance has increased
|
||||
|
||||
}
|
||||
|
||||
func TestSwap_Refund(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func watchForEvent(t *testing.T, contract *Swap) {
|
||||
watchOpts := &bind.WatchOpts{
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
ch := make(chan *SwapCalculatedPublicKey)
|
||||
|
||||
sub, err := contract.WatchCalculatedPublicKey(watchOpts, ch)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
go func() {
|
||||
for event := range ch {
|
||||
if event == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Println("got event")
|
||||
fmt.Println(event.Px, event.Py)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user