2022-09-21 02:50:11 +00:00
|
|
|
import std/options
|
2022-03-29 14:17:20 +00:00
|
|
|
import pkg/chronos
|
2022-09-20 07:17:40 +00:00
|
|
|
import pkg/ethers/testing
|
2022-05-19 19:56:03 +00:00
|
|
|
import codex/contracts
|
|
|
|
import codex/contracts/testtoken
|
2022-11-08 07:10:17 +00:00
|
|
|
import codex/storageproofs
|
2022-05-11 12:17:07 +00:00
|
|
|
import ../ethertest
|
2022-03-28 15:24:28 +00:00
|
|
|
import ./examples
|
2022-03-29 14:17:20 +00:00
|
|
|
import ./time
|
2022-03-28 15:24:28 +00:00
|
|
|
|
|
|
|
ethersuite "On-Chain Market":
|
2022-11-08 07:10:17 +00:00
|
|
|
let proof = exampleProof()
|
2022-03-28 15:24:28 +00:00
|
|
|
|
|
|
|
var market: OnChainMarket
|
|
|
|
var storage: Storage
|
|
|
|
var token: TestToken
|
2022-03-29 07:47:49 +00:00
|
|
|
var request: StorageRequest
|
2022-07-20 13:59:07 +00:00
|
|
|
var slotIndex: UInt256
|
2022-11-08 07:10:17 +00:00
|
|
|
var periodicity: Periodicity
|
2022-03-28 15:24:28 +00:00
|
|
|
|
|
|
|
setup:
|
|
|
|
let deployment = deployment()
|
|
|
|
storage = Storage.new(!deployment.address(Storage), provider.getSigner())
|
|
|
|
token = TestToken.new(!deployment.address(TestToken), provider.getSigner())
|
2022-07-20 13:59:07 +00:00
|
|
|
await token.mint(accounts[0], 1_000_000_000.u256)
|
2022-03-29 07:47:49 +00:00
|
|
|
|
|
|
|
let collateral = await storage.collateralAmount()
|
|
|
|
await token.approve(storage.address, collateral)
|
|
|
|
await storage.deposit(collateral)
|
|
|
|
|
2022-03-28 15:24:28 +00:00
|
|
|
market = OnChainMarket.new(storage)
|
2022-11-08 07:10:17 +00:00
|
|
|
periodicity = Periodicity(seconds: await storage.proofPeriod())
|
2022-03-28 15:24:28 +00:00
|
|
|
|
2022-03-29 07:47:49 +00:00
|
|
|
request = StorageRequest.example
|
|
|
|
request.client = accounts[0]
|
|
|
|
|
2022-07-20 13:59:07 +00:00
|
|
|
slotIndex = (request.ask.slots div 2).u256
|
|
|
|
|
2022-11-08 07:10:17 +00:00
|
|
|
proc waitUntilProofRequired(slotId: SlotId) {.async.} =
|
|
|
|
let currentPeriod = periodicity.periodOf(await provider.currentTime())
|
|
|
|
await provider.advanceTimeTo(periodicity.periodEnd(currentPeriod))
|
|
|
|
while not (
|
|
|
|
(await storage.isProofRequired(slotId)) and
|
|
|
|
(await storage.getPointer(slotId)) < 250
|
|
|
|
):
|
|
|
|
await provider.advanceTime(periodicity.seconds)
|
|
|
|
|
2022-03-28 15:28:51 +00:00
|
|
|
test "fails to instantiate when contract does not have a signer":
|
|
|
|
let storageWithoutSigner = storage.connect(provider)
|
|
|
|
expect AssertionError:
|
|
|
|
discard OnChainMarket.new(storageWithoutSigner)
|
|
|
|
|
2022-07-04 12:14:56 +00:00
|
|
|
test "knows signer address":
|
|
|
|
check (await market.getSigner()) == (await provider.getSigner().getAddress())
|
|
|
|
|
2022-03-28 15:24:28 +00:00
|
|
|
test "supports storage requests":
|
2022-07-20 13:59:07 +00:00
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-03-29 07:47:49 +00:00
|
|
|
|
2022-06-15 12:12:34 +00:00
|
|
|
test "can retrieve previously submitted requests":
|
|
|
|
check (await market.getRequest(request.id)) == none StorageRequest
|
2022-07-20 13:59:07 +00:00
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-09-07 11:02:00 +00:00
|
|
|
let r = await market.getRequest(request.id)
|
|
|
|
check (r) == some request
|
|
|
|
|
|
|
|
test "supports withdrawing of funds":
|
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-09-07 11:02:00 +00:00
|
|
|
await provider.advanceTimeTo(request.expiry)
|
|
|
|
await market.withdrawFunds(request.id)
|
2022-06-15 12:12:34 +00:00
|
|
|
|
2022-03-31 08:46:03 +00:00
|
|
|
test "supports request subscriptions":
|
2022-08-17 02:29:44 +00:00
|
|
|
var receivedIds: seq[RequestId]
|
2022-04-11 18:03:55 +00:00
|
|
|
var receivedAsks: seq[StorageAsk]
|
2022-08-17 02:29:44 +00:00
|
|
|
proc onRequest(id: RequestId, ask: StorageAsk) =
|
2022-04-11 18:03:55 +00:00
|
|
|
receivedIds.add(id)
|
|
|
|
receivedAsks.add(ask)
|
2022-03-29 07:47:49 +00:00
|
|
|
let subscription = await market.subscribeRequests(onRequest)
|
2022-07-20 13:59:07 +00:00
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-04-11 18:03:55 +00:00
|
|
|
check receivedIds == @[request.id]
|
|
|
|
check receivedAsks == @[request.ask]
|
2022-03-31 08:46:03 +00:00
|
|
|
await subscription.unsubscribe()
|
2022-03-29 07:47:49 +00:00
|
|
|
|
2022-07-20 13:59:07 +00:00
|
|
|
test "supports filling of slots":
|
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-07-20 13:59:07 +00:00
|
|
|
await market.fillSlot(request.id, slotIndex, proof)
|
2022-03-29 07:47:49 +00:00
|
|
|
|
2022-07-20 13:59:07 +00:00
|
|
|
test "can retrieve host that filled slot":
|
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-07-27 14:54:34 +00:00
|
|
|
check (await market.getHost(request.id, slotIndex)) == none Address
|
2022-07-20 13:59:07 +00:00
|
|
|
await market.fillSlot(request.id, slotIndex, proof)
|
2022-07-27 14:54:34 +00:00
|
|
|
check (await market.getHost(request.id, slotIndex)) == some accounts[0]
|
2022-07-04 10:11:18 +00:00
|
|
|
|
2022-07-28 12:33:17 +00:00
|
|
|
test "support slot filled subscriptions":
|
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-08-17 02:29:44 +00:00
|
|
|
var receivedIds: seq[RequestId]
|
2022-07-28 12:33:17 +00:00
|
|
|
var receivedSlotIndices: seq[UInt256]
|
2022-08-17 02:29:44 +00:00
|
|
|
proc onSlotFilled(id: RequestId, slotIndex: UInt256) =
|
2022-07-28 12:33:17 +00:00
|
|
|
receivedIds.add(id)
|
|
|
|
receivedSlotIndices.add(slotIndex)
|
|
|
|
let subscription = await market.subscribeSlotFilled(request.id, slotIndex, onSlotFilled)
|
|
|
|
await market.fillSlot(request.id, slotIndex, proof)
|
|
|
|
check receivedIds == @[request.id]
|
|
|
|
check receivedSlotIndices == @[slotIndex]
|
|
|
|
await subscription.unsubscribe()
|
|
|
|
|
|
|
|
test "subscribes only to a certain slot":
|
|
|
|
var otherSlot = slotIndex - 1
|
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-07-28 12:33:17 +00:00
|
|
|
var receivedSlotIndices: seq[UInt256]
|
2022-08-17 02:29:44 +00:00
|
|
|
proc onSlotFilled(requestId: RequestId, slotIndex: UInt256) =
|
2022-07-28 12:33:17 +00:00
|
|
|
receivedSlotIndices.add(slotIndex)
|
|
|
|
let subscription = await market.subscribeSlotFilled(request.id, slotIndex, onSlotFilled)
|
|
|
|
await market.fillSlot(request.id, slotIndex - 1, proof)
|
|
|
|
check receivedSlotIndices.len == 0
|
|
|
|
await market.fillSlot(request.id, slotIndex, proof)
|
|
|
|
check receivedSlotIndices == @[slotIndex]
|
|
|
|
await subscription.unsubscribe()
|
|
|
|
|
2022-06-14 07:47:05 +00:00
|
|
|
test "support fulfillment subscriptions":
|
2022-07-20 13:59:07 +00:00
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-08-17 02:29:44 +00:00
|
|
|
var receivedIds: seq[RequestId]
|
|
|
|
proc onFulfillment(id: RequestId) =
|
2022-06-14 07:47:05 +00:00
|
|
|
receivedIds.add(id)
|
|
|
|
let subscription = await market.subscribeFulfillment(request.id, onFulfillment)
|
2022-07-20 13:59:07 +00:00
|
|
|
for slotIndex in 0..<request.ask.slots:
|
|
|
|
await market.fillSlot(request.id, slotIndex.u256, proof)
|
2022-06-14 07:47:05 +00:00
|
|
|
check receivedIds == @[request.id]
|
2022-03-29 09:20:07 +00:00
|
|
|
await subscription.unsubscribe()
|
|
|
|
|
2022-07-20 13:59:07 +00:00
|
|
|
test "subscribes only to fulfillment of a certain request":
|
2022-03-29 09:20:07 +00:00
|
|
|
var otherRequest = StorageRequest.example
|
|
|
|
otherRequest.client = accounts[0]
|
|
|
|
|
2022-07-20 13:59:07 +00:00
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-08-26 04:08:02 +00:00
|
|
|
await token.approve(storage.address, otherRequest.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(otherRequest)
|
2022-03-29 09:20:07 +00:00
|
|
|
|
2022-08-17 02:29:44 +00:00
|
|
|
var receivedIds: seq[RequestId]
|
|
|
|
proc onFulfillment(id: RequestId) =
|
2022-06-14 07:47:05 +00:00
|
|
|
receivedIds.add(id)
|
2022-03-29 09:20:07 +00:00
|
|
|
|
2022-06-14 07:47:05 +00:00
|
|
|
let subscription = await market.subscribeFulfillment(request.id, onFulfillment)
|
2022-03-29 09:20:07 +00:00
|
|
|
|
2022-07-20 13:59:07 +00:00
|
|
|
for slotIndex in 0..<request.ask.slots:
|
|
|
|
await market.fillSlot(request.id, slotIndex.u256, proof)
|
|
|
|
for slotIndex in 0..<otherRequest.ask.slots:
|
|
|
|
await market.fillSlot(otherRequest.id, slotIndex.u256, proof)
|
2022-03-29 09:20:07 +00:00
|
|
|
|
2022-06-14 07:47:05 +00:00
|
|
|
check receivedIds == @[request.id]
|
2022-03-29 09:20:07 +00:00
|
|
|
|
|
|
|
await subscription.unsubscribe()
|
2022-09-07 11:02:00 +00:00
|
|
|
|
|
|
|
test "support request cancelled subscriptions":
|
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-09-07 11:02:00 +00:00
|
|
|
|
|
|
|
var receivedIds: seq[RequestId]
|
|
|
|
proc onRequestCancelled(id: RequestId) =
|
|
|
|
receivedIds.add(id)
|
|
|
|
let subscription = await market.subscribeRequestCancelled(request.id, onRequestCancelled)
|
|
|
|
|
|
|
|
await provider.advanceTimeTo(request.expiry)
|
|
|
|
await market.withdrawFunds(request.id)
|
|
|
|
check receivedIds == @[request.id]
|
|
|
|
await subscription.unsubscribe()
|
|
|
|
|
2022-11-08 07:10:17 +00:00
|
|
|
test "support request failed subscriptions":
|
|
|
|
await token.approve(storage.address, request.price)
|
|
|
|
await market.requestStorage(request)
|
|
|
|
|
|
|
|
var receivedIds: seq[RequestId]
|
|
|
|
proc onRequestFailed(id: RequestId) =
|
|
|
|
receivedIds.add(id)
|
|
|
|
let subscription = await market.subscribeRequestFailed(request.id, onRequestFailed)
|
|
|
|
|
|
|
|
for slotIndex in 0..<request.ask.slots:
|
|
|
|
await market.fillSlot(request.id, slotIndex.u256, proof)
|
|
|
|
for slotIndex in 0..request.ask.maxSlotLoss:
|
|
|
|
let slotId = request.slotId(slotIndex.u256)
|
|
|
|
while true:
|
|
|
|
try:
|
|
|
|
await waitUntilProofRequired(slotId)
|
|
|
|
let missingPeriod = periodicity.periodOf(await provider.currentTime())
|
|
|
|
await provider.advanceTime(periodicity.seconds)
|
|
|
|
await storage.markProofAsMissing(slotId, missingPeriod)
|
|
|
|
except ProviderError as e:
|
|
|
|
if e.revertReason == "Slot empty":
|
|
|
|
break
|
|
|
|
check receivedIds == @[request.id]
|
|
|
|
await subscription.unsubscribe()
|
|
|
|
|
2022-09-07 11:02:00 +00:00
|
|
|
test "subscribes only to a certain request cancellation":
|
2022-11-08 07:10:17 +00:00
|
|
|
var otherRequest = request
|
|
|
|
otherRequest.nonce = Nonce.example
|
2022-09-07 11:02:00 +00:00
|
|
|
await token.approve(storage.address, request.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(request)
|
2022-09-07 11:02:00 +00:00
|
|
|
await token.approve(storage.address, otherRequest.price)
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.requestStorage(otherRequest)
|
2022-09-07 11:02:00 +00:00
|
|
|
|
|
|
|
var receivedIds: seq[RequestId]
|
|
|
|
proc onRequestCancelled(requestId: RequestId) =
|
|
|
|
receivedIds.add(requestId)
|
|
|
|
|
|
|
|
let subscription = await market.subscribeRequestCancelled(request.id, onRequestCancelled)
|
|
|
|
await provider.advanceTimeTo(request.expiry) # shares expiry with otherRequest
|
2022-11-08 07:10:17 +00:00
|
|
|
await market.withdrawFunds(otherRequest.id)
|
2022-09-07 11:02:00 +00:00
|
|
|
check receivedIds.len == 0
|
|
|
|
await market.withdrawFunds(request.id)
|
|
|
|
check receivedIds == @[request.id]
|
|
|
|
await subscription.unsubscribe()
|
2022-09-21 02:50:11 +00:00
|
|
|
|
|
|
|
test "request is none when unknown":
|
|
|
|
check isNone await market.getRequest(request.id)
|
2022-11-08 07:10:17 +00:00
|
|
|
|
|
|
|
test "can retrieve active requests":
|
|
|
|
await token.approve(storage.address, request.price)
|
|
|
|
await market.requestStorage(request)
|
|
|
|
var request2 = StorageRequest.example
|
|
|
|
request2.client = accounts[0]
|
|
|
|
await token.approve(storage.address, request2.price)
|
|
|
|
await market.requestStorage(request2)
|
|
|
|
check (await market.myRequests()) == @[request.id, request2.id]
|
|
|
|
|
|
|
|
test "can retrieve request state":
|
|
|
|
await token.approve(storage.address, request.price)
|
|
|
|
await market.requestStorage(request)
|
|
|
|
for slotIndex in 0..<request.ask.slots:
|
|
|
|
await market.fillSlot(request.id, slotIndex.u256, proof)
|
|
|
|
check (await market.getState(request.id)) == some RequestState.Started
|