nim-nitro/tests/nitro/testWallet.nim

232 lines
9.0 KiB
Nim
Raw Normal View History

2021-03-09 16:53:15 +01:00
import ./basics
2021-03-15 16:19:29 +01:00
suite "wallet":
2021-03-18 14:15:58 +01:00
test "wallet is created from private key":
let key = EthPrivateKey.random()
2021-03-15 16:19:29 +01:00
let wallet = Wallet.init(key)
2021-04-06 13:49:06 +02:00
check wallet.publicKey == key.toPublicKey
2021-03-15 16:19:29 +01:00
check wallet.address == key.toPublicKey.toAddress
2021-04-06 13:49:06 +02:00
check wallet.destination == key.toPublicKey.toAddress.toDestination
2021-03-15 16:19:29 +01:00
suite "wallet: opening ledger channel":
2021-03-09 16:53:15 +01:00
let key = EthPrivateKey.random()
2021-03-09 16:53:15 +01:00
let asset = EthAddress.example
let amount = 42.u256
2021-03-15 16:19:29 +01:00
let hub = EthAddress.example
let chainId = UInt256.example
let nonce = UInt48.example
2021-03-09 16:53:15 +01:00
2021-03-15 16:19:29 +01:00
var wallet: Wallet
2021-03-17 12:53:30 +01:00
var channel: ChannelId
2021-03-09 16:53:15 +01:00
2021-03-15 16:19:29 +01:00
setup:
wallet = Wallet.init(key)
2021-04-19 16:11:30 +02:00
channel = !wallet.openLedgerChannel(hub, chainId, nonce, asset, amount)
2021-03-15 16:19:29 +01:00
test "sets correct channel definition":
2021-04-19 16:11:30 +02:00
let definition = (!wallet.state(channel)).channel
2021-03-16 12:50:46 +01:00
check definition.chainId == chainId
check definition.nonce == nonce
check definition.participants == @[wallet.address, hub]
2021-03-15 16:19:29 +01:00
2021-04-14 12:57:14 +02:00
test "uses consecutive nonces when none is provided":
2021-04-19 16:11:30 +02:00
channel = !wallet.openLedgerChannel(hub, chainId, asset, amount)
check (!wallet.state(channel)).channel.nonce == nonce + 1
channel = !wallet.openLedgerChannel(hub, chainId, asset, amount)
check (!wallet.state(channel)).channel.nonce == nonce + 2
2021-04-14 12:57:14 +02:00
2021-03-15 16:19:29 +01:00
test "provides correct outcome":
2021-04-19 16:11:30 +02:00
let outcome = (!wallet.state(channel)).outcome
2021-03-18 14:15:58 +01:00
check outcome == Outcome.init(asset, {wallet.destination: amount})
2021-03-15 16:19:29 +01:00
2021-03-17 12:53:30 +01:00
test "signs the state":
2021-04-19 16:11:30 +02:00
let state = !wallet.state(channel)
let signatures = !wallet.signatures(channel)
check signatures == @[key.sign(state)]
2021-03-15 16:19:29 +01:00
test "sets app definition and app data to zero":
2021-04-19 16:11:30 +02:00
check (!wallet.state(channel)).appDefinition == EthAddress.zero
check (!wallet.state(channel)).appData.len == 0
2021-03-16 12:50:46 +01:00
test "does not allow opening a channel that already exists":
check wallet.openLedgerChannel(hub, chainId, nonce, asset, amount).isFailure
2021-03-16 12:50:46 +01:00
suite "wallet: accepting incoming channel":
let key = EthPrivateKey.random()
2021-03-16 12:50:46 +01:00
var wallet: Wallet
2021-03-17 13:10:49 +01:00
var signed: SignedState
2021-03-16 12:50:46 +01:00
setup:
wallet = Wallet.init(key)
2021-03-17 13:10:49 +01:00
signed = SignedState(state: State.example)
signed.state.channel.participants &= @[wallet.address]
2021-03-16 12:50:46 +01:00
2021-03-17 12:53:30 +01:00
test "returns the new channel id":
2021-04-19 16:11:30 +02:00
let channel = !wallet.acceptChannel(signed)
check !wallet.state(channel) == signed.state
2021-03-16 12:50:46 +01:00
test "signs the channel state":
2021-04-19 16:11:30 +02:00
let channel = !wallet.acceptChannel(signed)
let expectedSignatures = @[key.sign(signed.state)]
2021-04-19 16:11:30 +02:00
check !wallet.signatures(channel) == expectedSignatures
2021-03-16 12:50:46 +01:00
test "fails when wallet address is not a participant":
let wrongParticipants = seq[EthAddress].example
2021-03-17 13:10:49 +01:00
signed.state.channel.participants = wrongParticipants
check wallet.acceptChannel(signed).isFailure
2021-03-16 12:50:46 +01:00
test "fails when signatures are incorrect":
signed.signatures = @[key.sign(State.example)]
check wallet.acceptChannel(signed).isFailure
2021-03-18 14:15:58 +01:00
test "fails when channel with this id already exists":
check wallet.acceptChannel(signed).isSuccess
check wallet.acceptChannel(signed).isFailure
2021-03-18 14:15:58 +01:00
suite "wallet: making payments":
let key = EthPrivateKey.random()
2021-03-18 14:15:58 +01:00
let asset = EthAddress.example
let hub = EthAddress.example
let chainId = UInt256.example
let nonce = UInt48.example
var wallet: Wallet
var channel: ChannelId
test "paying updates the channel state":
wallet = Wallet.init(key)
2021-04-19 16:11:30 +02:00
channel = !wallet.openLedgerChannel(hub, chainId, nonce, asset, 100.u256)
2021-03-18 14:15:58 +01:00
check wallet.pay(channel, asset, hub, 1.u256).isSuccess
check wallet.balance(channel, asset) == 99.u256
2021-03-18 14:15:58 +01:00
check wallet.balance(channel, asset, hub) == 1.u256
check wallet.pay(channel, asset, hub, 2.u256).isSuccess
check wallet.balance(channel, asset) == 97.u256
2021-03-18 14:15:58 +01:00
check wallet.balance(channel, asset, hub) == 3.u256
test "paying updates signatures":
wallet = Wallet.init(key)
2021-04-19 16:11:30 +02:00
channel = !wallet.openLedgerChannel(hub, chainId, nonce, asset, 100.u256)
check wallet.pay(channel, asset, hub, 1.u256).isSuccess
2021-04-19 16:11:30 +02:00
let expectedSignature = key.sign(!wallet.state(channel))
2021-03-18 14:15:58 +01:00
check wallet.signature(channel, wallet.address) == expectedSignature.some
test "pay returns the updated signed state":
wallet = Wallet.init(key)
2021-04-19 16:11:30 +02:00
channel = !wallet.openLedgerChannel(hub, chainId, nonce, asset, 42.u256)
let updated = wallet.pay(channel, asset, hub, 1.u256).option
2021-04-12 16:29:44 +02:00
check updated.?state == wallet.state(channel)
check updated.?signatures == wallet.signatures(channel)
2021-03-18 14:15:58 +01:00
test "payment fails when channel not found":
wallet = Wallet.init(key)
check wallet.pay(channel, asset, hub, 1.u256).isFailure
2021-03-18 14:15:58 +01:00
test "payment fails when asset not found":
wallet = Wallet.init(key)
var state = State.example
state.channel.participants &= wallet.address
2021-04-19 16:11:30 +02:00
channel = !wallet.acceptChannel(SignedState(state: state))
check wallet.pay(channel, asset, hub, 1.u256).isFailure
2021-03-18 14:15:58 +01:00
test "payment fails when payer has no allocation":
wallet = Wallet.init(key)
var state: State
state.channel = ChannelDefinition(participants: @[wallet.address])
state.outcome = Outcome.init(asset, @[])
2021-04-19 16:11:30 +02:00
channel = !wallet.acceptChannel(SignedState(state: state))
check wallet.pay(channel, asset, hub, 1.u256).isFailure
2021-03-18 14:15:58 +01:00
test "payment fails when payer has insufficient funds":
wallet = Wallet.init(key)
2021-04-19 16:11:30 +02:00
channel = !wallet.openLedgerChannel(hub, chainId, nonce, asset, 1.u256)
check wallet.pay(channel, asset, hub, 1.u256).isSuccess
check wallet.pay(channel, asset, hub, 1.u256).isFailure
2021-03-22 14:04:28 +01:00
suite "wallet: accepting payments":
let payerKey, receiverKey = EthPrivateKey.random()
2021-03-22 14:04:28 +01:00
let asset = EthAddress.example
let chainId = UInt256.example
let nonce = UInt48.example
var payer, receiver: Wallet
var channel: ChannelId
setup:
payer = Wallet.init(payerKey)
receiver = Wallet.init(receiverKey)
2021-04-19 16:11:30 +02:00
channel = !payer.openLedgerChannel(
receiver.address, chainId, nonce, asset, 100.u256)
let update = !payer.latestSignedState(channel)
2021-03-22 14:04:28 +01:00
discard receiver.acceptChannel(update)
test "updates channel state":
2021-04-19 16:11:30 +02:00
let payment = !payer.pay(channel, asset, receiver.address, 42.u256)
check receiver.acceptPayment(channel, asset, payer.address, payment).isSuccess
check receiver.balance(channel, asset) == 42.u256
2021-03-22 14:04:28 +01:00
test "fails when receiver balance is decreased":
2021-04-19 16:11:30 +02:00
let payment1 = !payer.pay(channel, asset, receiver.address, 10.u256)
let payment2 = !payer.pay(channel, asset, receiver.address, 10.u256)
check receiver.acceptPayment(channel, asset, payer.address, payment1).isSuccess
check receiver.acceptPayment(channel, asset, payer.address, payment2).isSuccess
check receiver.acceptPayment(channel, asset, payer.address, payment1).isFailure
check receiver.balance(channel, asset) == 20
2021-03-22 14:04:28 +01:00
test "fails when the total supply of the asset changes":
2021-04-19 16:11:30 +02:00
var payment = !payer.pay(channel, asset, receiver.address, 10.u256)
var balances = !payment.state.outcome.balances(asset)
2021-03-22 14:04:28 +01:00
balances[payer.destination] += 10.u256
payment.state.outcome.update(asset, balances)
check receiver.acceptPayment(channel, asset, payer.address, payment).isFailure
2021-03-22 14:04:28 +01:00
test "fails without a signature":
2021-04-19 16:11:30 +02:00
var payment = !payer.pay(channel, asset, receiver.address, 10.u256)
2021-03-22 14:04:28 +01:00
payment.signatures = @[]
check receiver.acceptPayment(channel, asset, payer.address, payment).isFailure
2021-03-22 14:04:28 +01:00
test "fails with an incorrect signature":
2021-04-19 16:11:30 +02:00
var payment = !payer.pay(channel, asset, receiver.address, 10.u256)
payment.signatures = @[Signature.example]
check receiver.acceptPayment(channel, asset, payer.address, payment).isFailure
2021-03-22 14:04:28 +01:00
test "fails when channel is unknown":
2021-04-19 16:11:30 +02:00
let newChannel = !payer.openLedgerChannel(
receiver.address, chainId, nonce + 1, asset, 100.u256)
let payment = !payer.pay(newChannel, asset, receiver.address, 10.u256)
check receiver.acceptPayment(newChannel, asset, payer.address, payment).isFailure
2021-03-22 14:04:28 +01:00
test "fails when payment does not match channel":
2021-04-19 16:11:30 +02:00
let newChannel = !payer.openLedgerChannel(
receiver.address, chainId, nonce + 1, asset, 100.u256)
let payment = !payer.pay(newChannel, asset, receiver.address, 10.u256)
check receiver.acceptPayment(channel, asset, payer.address, payment).isFailure
test "fails when state is updated in unrelated areas":
2021-04-19 16:11:30 +02:00
var payment = !payer.pay(channel, asset, receiver.address, 10.u256)
payment.state.appDefinition = EthAddress.example
payment.signatures = @[payerKey.sign(payment.state)]
check receiver.acceptPayment(channel, asset, payer.address, payment).isFailure
suite "wallet reference type":
let asset = EthAddress.example
let amount = 42.u256
let chainId = UInt256.example
test "wallet can also be used as a reference type":
let wallet1 = WalletRef.new(EthPrivateKey.random())
let wallet2 = WalletRef.new(EthPrivateKey.random())
let address1 = wallet1.address
let address2 = wallet2.address
let channel = !wallet1.openLedgerChannel(address2, chainId, asset, amount)
check !wallet2.acceptChannel(!wallet1.latestSignedState(channel)) == channel
let payment = !wallet1.pay(channel, asset, address2, amount)
check wallet2.acceptPayment(channel, asset, address1, payment).isSuccess