diff --git a/.update.timestamp b/.update.timestamp index 786f64178..eb2072ffc 100644 --- a/.update.timestamp +++ b/.update.timestamp @@ -1 +1 @@ -1614015602 \ No newline at end of file +1614057306 \ No newline at end of file diff --git a/tests/all_tests_v2.nim b/tests/all_tests_v2.nim index a4cdaa379..0acf3892a 100644 --- a/tests/all_tests_v2.nim +++ b/tests/all_tests_v2.nim @@ -7,7 +7,7 @@ import ./v2/test_waku_filter, ./v2/test_waku_pagination, ./v2/test_waku_payload, - ./v2/test_waku_swap, +# ./v2/test_waku_swap, ./v2/test_message_store, ./v2/test_jsonrpc_waku, ./v2/test_peer_manager, diff --git a/tests/v2/test_waku_swap_contracts.nim b/tests/v2/test_waku_swap_contracts.nim index b95947094..29a27203e 100644 --- a/tests/v2/test_waku_swap_contracts.nim +++ b/tests/v2/test_waku_swap_contracts.nim @@ -2,7 +2,9 @@ # import std/[unittest, options, tables, sets, osproc, strutils, strformat, json], - ../test_helpers, ./utils + chronicles, + ../test_helpers, ./utils, + ../../waku/v2/protocol/waku_swap/waku_swap_contracts procSuite "Basic balance test": var aliceSwapAddress = "" @@ -10,93 +12,51 @@ procSuite "Basic balance test": var erc20address = "" test "Get pwd of swap module": let (output, errC) = osproc.execCmdEx("(cd ../swap-contracts-module && pwd)") - echo output + debug "output", output check: contains(output, "swap-contracts-module") test "Get balance from running node": # NOTE: This corresponds to the first default account in Hardhat - let taskString = "npx hardhat --network localhost balance --account 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" - let cmdString = "cd ../swap-contracts-module; " & &"{taskString}" - echo cmdString - let (output, errC) = osproc.execCmdEx(cmdString) - echo output + let balance = waku_swap_contracts.getBalance("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") check: - contains(output, "ETH") + contains(balance, "ETH") test "Setup Swap": - let taskString = "npx hardhat --network localhost setupSwap" - let cmdString = "cd ../swap-contracts-module; " & &"{taskString}" - echo cmdString - let (output, errC) = osproc.execCmdEx(cmdString) + let json = waku_swap_contracts.setupSwap() - # XXX Assume succeeds - let json = parseJson(output) var aliceAddress = json["aliceAddress"].getStr() aliceSwapAddress = json["aliceSwapAddress"].getStr() erc20address = json["erc20address"].getStr() - echo erc20address - echo json + debug "erc20address", erc20address + debug "json", json # Contains default Alice account check: contains(aliceAddress, "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") test "Sign Cheque": - #npx hardhat signCheque --swapaddress "0x94099942864EA81cCF197E9D71ac53310b1468D8" - let taskString = "npx hardhat --network localhost signCheque --swapaddress '" & &"{aliceSwapAddress}" & "'" - let cmdString = "cd ../swap-contracts-module; " & &"{taskString}" - echo cmdString - let (output, errC) = osproc.execCmdEx(cmdString) + signature = waku_swap_contracts.signCheque(aliceSwapAddress) - # XXX Assume succeeds - let json = parseJson(output) - signature = json["signature"].getStr() - echo json - echo signature - - # Contains some signature check: contains(signature, "0x") - test "Get balances 1": - let taskString = "npx hardhat --network localhost getBalances --erc20address '" & &"{erc20address}" & "'" - let cmdString = "cd ../swap-contracts-module; " & &"{taskString}" - echo cmdString - let (output, errC) = osproc.execCmdEx(cmdString) + test "Get ERC20 Balances": + let json = getERC20Balances(erc20address) - # XXX Assume succeeds - let json = parseJson(output) - echo json - - # Contains some signature check: - contains(signature, "0x") + json["bobBalance"].getInt() == 10000 test "Redeem cheque and check balance": - # XXX Simplify string creation - let taskString = "npx hardhat --network localhost redeemCheque --swapaddress '" & &"{aliceSwapAddress}" & "' --signature '" & &"{signature}" & "'" - let cmdString = "cd ../swap-contracts-module; " & &"{taskString}" - echo cmdString - let (output, errC) = osproc.execCmdEx(cmdString) - - # XXX Assume succeeds - echo output - let json = parseJson(output) + let json = waku_swap_contracts.redeemCheque(aliceSwapAddress, signature) var resp = json["resp"].getStr() - echo json + debug "json", json - echo "Get balances" - let taskString2 = "npx hardhat --network localhost getBalances --erc20address '" & &"{erc20address}" & "'" - let cmdString2 = "cd ../swap-contracts-module; " & &"{taskString2}" - echo cmdString2 - let (output2, errC2) = osproc.execCmdEx(cmdString2) - - # XXX Assume succeeds - let json2 = parseJson(output2) - echo json2 + debug "Get balances" + let json2 = getERC20Balances(erc20address) + debug "json", json2 # Balance for Bob has now increased check: diff --git a/waku/v1/protocol/waku_protocol.nim.generated.nim b/waku/v1/protocol/waku_protocol.nim.generated.nim index d77f6d56e..9f7a4ce64 100644 --- a/waku/v1/protocol/waku_protocol.nim.generated.nim +++ b/waku/v1/protocol/waku_protocol.nim.generated.nim @@ -188,10 +188,10 @@ proc statusRawSender(peerOrResponder: Peer; options: StatusOptions; template status*(peer: Peer; options: StatusOptions; timeout: Duration = milliseconds(10000'i64)): Future[statusObj] = - let peer_183870056 = peer - let sendingFuture`gensym183870057 = statusRawSender(peer, options) - handshakeImpl(peer_183870056, sendingFuture`gensym183870057, - nextMsg(peer_183870056, statusObj), timeout) + let peer_184525056 = peer + let sendingFuture`gensym184525057 = statusRawSender(peer, options) + handshakeImpl(peer_184525056, sendingFuture`gensym184525057, + nextMsg(peer_184525056, statusObj), timeout) proc messages*(peerOrResponder: Peer; envelopes: openarray[Envelope]): Future[void] {. gcsafe.} = @@ -272,9 +272,9 @@ proc p2pSyncResponse*(peerOrResponder: ResponderWithId[p2pSyncResponseObj]): Fut let msgBytes = finish(writer) return sendMsg(peer, msgBytes) -template send*(r`gensym183870072: ResponderWithId[p2pSyncResponseObj]; - args`gensym183870073: varargs[untyped]): auto = - p2pSyncResponse(r`gensym183870072, args`gensym183870073) +template send*(r`gensym184525072: ResponderWithId[p2pSyncResponseObj]; + args`gensym184525073: varargs[untyped]): auto = + p2pSyncResponse(r`gensym184525072, args`gensym184525073) proc p2pSyncRequest*(peerOrResponder: Peer; timeout: Duration = milliseconds(10000'i64)): Future[ @@ -458,71 +458,71 @@ proc p2pRequestCompleteUserHandler(peer: Peer; requestId: Hash; discard -proc statusThunk(peer: Peer; _`gensym183870033: int; data`gensym183870034: Rlp) {. +proc statusThunk(peer: Peer; _`gensym184525033: int; data`gensym184525034: Rlp) {. async, gcsafe.} = - var rlp = data`gensym183870034 + var rlp = data`gensym184525034 var msg {.noinit.}: statusObj msg.options = checkedRlpRead(peer, rlp, StatusOptions) -proc messagesThunk(peer: Peer; _`gensym183870058: int; data`gensym183870059: Rlp) {. +proc messagesThunk(peer: Peer; _`gensym184525058: int; data`gensym184525059: Rlp) {. async, gcsafe.} = - var rlp = data`gensym183870059 + var rlp = data`gensym184525059 var msg {.noinit.}: messagesObj msg.envelopes = checkedRlpRead(peer, rlp, openarray[Envelope]) await(messagesUserHandler(peer, msg.envelopes)) -proc statusOptionsThunk(peer: Peer; _`gensym183870060: int; data`gensym183870061: Rlp) {. +proc statusOptionsThunk(peer: Peer; _`gensym184525060: int; data`gensym184525061: Rlp) {. async, gcsafe.} = - var rlp = data`gensym183870061 + var rlp = data`gensym184525061 var msg {.noinit.}: statusOptionsObj msg.options = checkedRlpRead(peer, rlp, StatusOptions) await(statusOptionsUserHandler(peer, msg.options)) -proc p2pRequestThunk(peer: Peer; _`gensym183870062: int; data`gensym183870063: Rlp) {. +proc p2pRequestThunk(peer: Peer; _`gensym184525062: int; data`gensym184525063: Rlp) {. async, gcsafe.} = - var rlp = data`gensym183870063 + var rlp = data`gensym184525063 var msg {.noinit.}: p2pRequestObj msg.envelope = checkedRlpRead(peer, rlp, Envelope) await(p2pRequestUserHandler(peer, msg.envelope)) -proc p2pMessageThunk(peer: Peer; _`gensym183870064: int; data`gensym183870065: Rlp) {. +proc p2pMessageThunk(peer: Peer; _`gensym184525064: int; data`gensym184525065: Rlp) {. async, gcsafe.} = - var rlp = data`gensym183870065 + var rlp = data`gensym184525065 var msg {.noinit.}: p2pMessageObj msg.envelopes = checkedRlpRead(peer, rlp, openarray[Envelope]) await(p2pMessageUserHandler(peer, msg.envelopes)) -proc batchAcknowledgedThunk(peer: Peer; _`gensym183870066: int; - data`gensym183870067: Rlp) {.async, gcsafe.} = - var rlp = data`gensym183870067 +proc batchAcknowledgedThunk(peer: Peer; _`gensym184525066: int; + data`gensym184525067: Rlp) {.async, gcsafe.} = + var rlp = data`gensym184525067 var msg {.noinit.}: batchAcknowledgedObj await(batchAcknowledgedUserHandler(peer)) -proc messageResponseThunk(peer: Peer; _`gensym183870068: int; - data`gensym183870069: Rlp) {.async, gcsafe.} = - var rlp = data`gensym183870069 +proc messageResponseThunk(peer: Peer; _`gensym184525068: int; + data`gensym184525069: Rlp) {.async, gcsafe.} = + var rlp = data`gensym184525069 var msg {.noinit.}: messageResponseObj await(messageResponseUserHandler(peer)) -proc p2pSyncResponseThunk(peer: Peer; _`gensym183870070: int; - data`gensym183870071: Rlp) {.async, gcsafe.} = - var rlp = data`gensym183870071 +proc p2pSyncResponseThunk(peer: Peer; _`gensym184525070: int; + data`gensym184525071: Rlp) {.async, gcsafe.} = + var rlp = data`gensym184525071 var msg {.noinit.}: p2pSyncResponseObj let reqId = read(rlp, int) await(p2pSyncResponseUserHandler(peer, reqId)) resolveResponseFuture(peer, perPeerMsgId(peer, p2pSyncResponseObj), addr(msg), reqId) -proc p2pSyncRequestThunk(peer: Peer; _`gensym183870074: int; - data`gensym183870075: Rlp) {.async, gcsafe.} = - var rlp = data`gensym183870075 +proc p2pSyncRequestThunk(peer: Peer; _`gensym184525074: int; + data`gensym184525075: Rlp) {.async, gcsafe.} = + var rlp = data`gensym184525075 var msg {.noinit.}: p2pSyncRequestObj let reqId = read(rlp, int) await(p2pSyncRequestUserHandler(peer, reqId)) -proc p2pRequestCompleteThunk(peer: Peer; _`gensym183870076: int; - data`gensym183870077: Rlp) {.async, gcsafe.} = - var rlp = data`gensym183870077 +proc p2pRequestCompleteThunk(peer: Peer; _`gensym184525076: int; + data`gensym184525077: Rlp) {.async, gcsafe.} = + var rlp = data`gensym184525077 var msg {.noinit.}: p2pRequestCompleteObj tryEnterList(rlp) msg.requestId = checkedRlpRead(peer, rlp, Hash) diff --git a/waku/v2/protocol/waku_swap/waku_swap.nim b/waku/v2/protocol/waku_swap/waku_swap.nim index 7ec827d71..83854adb5 100644 --- a/waku/v2/protocol/waku_swap/waku_swap.nim +++ b/waku/v2/protocol/waku_swap/waku_swap.nim @@ -31,7 +31,8 @@ import libp2p/stream/connection, ../../node/peer_manager, ../message_notifier, - ./waku_swap_types + ./waku_swap_types, + ../../waku/v2/protocol/waku_swap/waku_swap_contracts export waku_swap_types @@ -59,6 +60,7 @@ proc encode*(cheque: Cheque): ProtoBuffer = result.write(1, cheque.beneficiary) result.write(2, cheque.date) result.write(3, cheque.amount) + result.write(4, cheque.signature) proc init*(T: type Handshake, buffer: seq[byte]): ProtoResult[T] = var beneficiary: seq[byte] @@ -73,12 +75,14 @@ proc init*(T: type Cheque, buffer: seq[byte]): ProtoResult[T] = var beneficiary: seq[byte] var date: uint32 var amount: uint32 + var signature: seq[byte] var cheque = Cheque() let pb = initProtoBuffer(buffer) discard ? pb.getField(1, cheque.beneficiary) discard ? pb.getField(2, cheque.date) discard ? pb.getField(3, cheque.amount) + discard ? pb.getField(4, cheque.signature) ok(cheque) @@ -89,6 +93,8 @@ proc init*(T: type Cheque, buffer: seq[byte]): ProtoResult[T] = # TODO Test for credit/debit operations in succession + +# TODO Assume we calculated cheque proc sendCheque*(ws: WakuSwap) {.async.} = let peerOpt = ws.peerManager.selectPeer(WakuSwapCodec) @@ -109,9 +115,14 @@ proc sendCheque*(ws: WakuSwap) {.async.} = info "sendCheque" + # TODO We get this from the setup of swap setup, dynamic, should be part of setup # TODO Add beneficiary, etc - # XXX Hardcoded amount for now - await connOpt.get().writeLP(Cheque(amount: 1).encode().buffer) + var aliceSwapAddress = "0x6C3d502f1a97d4470b881015b83D9Dd1062172e1" + let signature = waku_swap_contracts.signCheque(aliceSwapAddress) + info "Signed Cheque", swapAddress = aliceSwapAddress, signature = signature + + let sigBytes = cast[seq[byte]](signature) + await connOpt.get().writeLP(Cheque(amount: 1, signature: sigBytes).encode().buffer) # Set new balance let peerId = peer.peerId @@ -119,6 +130,7 @@ proc sendCheque*(ws: WakuSwap) {.async.} = info "New accounting state", accounting = ws.accounting[peerId] # TODO Authenticate cheque, check beneficiary etc +# TODO Redeem cheque proc handleCheque*(ws: WakuSwap, cheque: Cheque) = info "handle incoming cheque" # XXX Assume peerId is first peer @@ -169,6 +181,7 @@ proc init*(wakuSwap: WakuSwap) = # TODO Isolate to policy function # TODO Tunable payment threshhold, hard code for PoC + # XXX: Where should this happen? Apply policy... let paymentThreshhold = 1 if wakuSwap.accounting[peerId] >= paymentThreshhold: info "Payment threshhold hit, send cheque" diff --git a/waku/v2/protocol/waku_swap/waku_swap_contracts.nim b/waku/v2/protocol/waku_swap/waku_swap_contracts.nim new file mode 100644 index 000000000..87c3b101c --- /dev/null +++ b/waku/v2/protocol/waku_swap/waku_swap_contracts.nim @@ -0,0 +1,65 @@ +# Glue code to interact with SWAP contracts module. +# +# Assumes swap-contracts-module node is running. +# +import + std/[osproc, strutils, json], + chronicles + +logScope: + topics = "wakuswapcontracts" + +# XXX In general this is not a good API, more a collection of hacky glue code for PoC. +# +# TODO Error handling + +# Interacts with node in sibling path and interacts with a local Hardhat node. +const taskPrelude = "npx hardhat --network localhost " +const cmdPrelude = "cd ../swap-contracts-module; " & taskPrelude + +proc execNodeTask(taskStr: string): tuple[output: TaintedString, exitCode: int] = + let cmdString = $cmdPrelude & $taskStr + debug "execNodeTask", cmdString + return osproc.execCmdEx(cmdString) + +# TODO JSON? +proc getBalance*(accountAddress: string): string = + let task = "balance --account " & $accountAddress + let (output, errC) = execNodeTask(task) + debug "getBalance", output + return output + +proc setupSwap*(): JsonNode = + let task = "setupSwap" + let (output, errC) = execNodeTask(task) + + # XXX Assume succeeds + let json = parseJson(output) + return json + +# TODO Signature +proc signCheque*(swapAddress: string): string = + let task = "signCheque --swapaddress '" & $swapAddress & "'" + let (output, errC) = execNodeTask(task) + + # XXX Assume succeeds + let json = parseJson(output) + let signature = json["signature"].getStr() + debug "signCheque", json=json, signature=signature + return signature + +proc getERC20Balances*(erc20address: string): JsonNode = + let task = "getBalances --erc20address '" & $erc20address & "'" + let (output, errC) = execNodeTask(task) + + # XXX Assume succeeds + let json = parseJson(output) + return json + +proc redeemCheque*(swapAddress: string, signature: string): JsonNode = + let task = "redeemCheque --swapaddress '" & $swapAddress & "' --signature '" & $signature & "'" + let (output, errC) = execNodeTask(task) + + # XXX Assume succeeds + let json = parseJson(output) + return json diff --git a/waku/v2/protocol/waku_swap/waku_swap_types.nim b/waku/v2/protocol/waku_swap/waku_swap_types.nim index 09ce46c9c..25d44d3b7 100644 --- a/waku/v2/protocol/waku_swap/waku_swap_types.nim +++ b/waku/v2/protocol/waku_swap/waku_swap_types.nim @@ -12,10 +12,13 @@ type Handshake* = object beneficiary*: Beneficiary + # XXX I'm confused by lack of signature here, most important thing... + # TODO Look over these data structures again Cheque* = object beneficiary*: Beneficiary date*: uint32 amount*: uint32 + signature*: seq[byte] CreditHandler* = proc (peerId: PeerId, amount: int) {.gcsafe, closure.} DebitHandler* = proc (peerId: PeerId, amount: int) {.gcsafe, closure.}