From 9f76e714a218f58c074bf43e7e6cfdbb9bc7a4f7 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 29 Mar 2022 09:47:49 +0200 Subject: [PATCH] [market] submit storage offers --- dagger/contracts/market.nim | 22 ++++++++-- dagger/contracts/offers.nim | 22 ++++++---- dagger/contracts/storage.nim | 6 ++- tests/contracts/testMarket.nim | 74 +++++++++++++++++++++++++++++----- 4 files changed, 102 insertions(+), 22 deletions(-) diff --git a/dagger/contracts/market.nim b/dagger/contracts/market.nim index 175e3cf6..008d2726 100644 --- a/dagger/contracts/market.nim +++ b/dagger/contracts/market.nim @@ -20,6 +20,16 @@ func new*(_: type OnChainMarket, contract: Storage): OnChainMarket = raiseAssert("Storage contract should have a signer") OnChainMarket(contract: contract, signer: signer) +method requestStorage(market: OnChainMarket, request: StorageRequest) {.async.} = + var request = request + request.client = await market.signer.getAddress() + await market.contract.requestStorage(request) + +method offerStorage(market: OnChainMarket, offer: StorageOffer) {.async.} = + var offer = offer + offer.host = await market.signer.getAddress() + await market.contract.offerStorage(offer) + method subscribeRequests(market: OnChainMarket, callback: OnRequest): Future[MarketSubscription] {.async.} = @@ -28,10 +38,14 @@ method subscribeRequests(market: OnChainMarket, let subscription = await market.contract.subscribe(StorageRequested, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) -method requestStorage(market: OnChainMarket, request: StorageRequest) {.async.} = - var request = request - request.client = await market.signer.getAddress() - await market.contract.requestStorage(request) +method subscribeOffers(market: OnChainMarket, + requestId: array[32, byte], + callback: OnOffer): + Future[MarketSubscription] {.async.} = + proc onEvent(event: StorageOffered) {.upraises:[].} = + callback(event.offer) + let subscription = await market.contract.subscribe(StorageOffered, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method unsubscribe*(subscription: OnChainMarketSubscription) {.async.} = await subscription.eventSubscription.unsubscribe() diff --git a/dagger/contracts/offers.nim b/dagger/contracts/offers.nim index 0bfdceda..5f23f183 100644 --- a/dagger/contracts/offers.nim +++ b/dagger/contracts/offers.nim @@ -1,5 +1,7 @@ import pkg/contractabi import pkg/nimcrypto +import pkg/ethers/fields +import pkg/questionable/results export contractabi @@ -10,19 +12,23 @@ type price*: UInt256 expiry*: UInt256 -func toTuple(offer: StorageOffer): auto = - ( - offer.host, - offer.requestId, - offer.price, - offer.expiry +func fromTuple(_: type StorageOffer, tupl: tuple): StorageOffer = + StorageOffer( + host: tupl[0], + requestId: tupl[1], + price: tupl[2], + expiry: tupl[3] ) func solidityType*(_: type StorageOffer): string = - solidityType(typeof StorageOffer.default.toTuple) + solidityType(StorageOffer.fieldTypes) func encode*(encoder: var AbiEncoder, offer: StorageOffer) = - encoder.write(offer.toTuple) + encoder.write(offer.fieldValues) + +func decode*(decoder: var AbiDecoder, T: type StorageOffer): ?!T = + let tupl = ?decoder.read(StorageOffer.fieldTypes) + success StorageOffer.fromTuple(tupl) func id*(offer: StorageOffer): array[32, byte] = let encoding = AbiEncoder.encode(offer) diff --git a/dagger/contracts/storage.nim b/dagger/contracts/storage.nim index f88582dd..b30813f5 100644 --- a/dagger/contracts/storage.nim +++ b/dagger/contracts/storage.nim @@ -6,7 +6,7 @@ import ./requests import ./offers export stint -export contract +export ethers type Storage* = ref object of Contract @@ -14,6 +14,10 @@ type StorageRequested* = object of Event requestId*: Id request*: StorageRequest + StorageOffered* = object of Event + offerId*: Id + offer*: StorageOffer + requestId* {.indexed.}: Id proc collateralAmount*(storage: Storage): UInt256 {.contract, view.} proc slashMisses*(storage: Storage): UInt256 {.contract, view.} diff --git a/tests/contracts/testMarket.nim b/tests/contracts/testMarket.nim index 6bc29399..6c86ca9b 100644 --- a/tests/contracts/testMarket.nim +++ b/tests/contracts/testMarket.nim @@ -1,3 +1,4 @@ +import std/times import ./ethertest import dagger/contracts import dagger/contracts/testtoken @@ -8,14 +9,28 @@ ethersuite "On-Chain Market": var market: OnChainMarket var storage: Storage var token: TestToken + var request: StorageRequest + var offer: StorageOffer setup: let deployment = deployment() storage = Storage.new(!deployment.address(Storage), provider.getSigner()) token = TestToken.new(!deployment.address(TestToken), provider.getSigner()) await token.mint(accounts[0], 1000.u256) + + let collateral = await storage.collateralAmount() + await token.approve(storage.address, collateral) + await storage.deposit(collateral) + market = OnChainMarket.new(storage) + request = StorageRequest.example + offer = StorageOffer.example + request.client = accounts[0] + offer.host = accounts[0] + offer.requestId = request.id + offer.price = request.maxPrice + test "fails to instantiate when contract does not have a signer": let storageWithoutSigner = storage.connect(provider) expect AssertionError: @@ -26,14 +41,55 @@ ethersuite "On-Chain Market": proc onRequest(request: StorageRequest) = submitted.add(request) let subscription = await market.subscribeRequests(onRequest) - let request = StorageRequest( - duration: uint16.example.u256, - size: uint32.example.u256, - contentHash: array[32, byte].example - ) + await token.approve(storage.address, request.maxPrice) + await market.requestStorage(request) - check submitted.len == 1 - check submitted[0].duration == request.duration - check submitted[0].size == request.size - check submitted[0].contentHash == request.contentHash + + check submitted == @[request] + await subscription.unsubscribe() + + test "sets client address when submitting storage request": + var requestWithoutClient = request + requestWithoutClient.client = Address.default + + var submitted: StorageRequest + proc onRequest(request: StorageRequest) = + submitted = request + let subscription = await market.subscribeRequests(onRequest) + await token.approve(storage.address, request.maxPrice) + + await market.requestStorage(requestWithoutClient) + + check submitted.client == accounts[0] + + test "supports storage offers": + await token.approve(storage.address, request.maxPrice) + await market.requestStorage(request) + + var submitted: seq[StorageOffer] + proc onOffer(offer: StorageOffer) = + submitted.add(offer) + let subscription = await market.subscribeOffers(request.id, onOffer) + + await market.offerStorage(offer) + + check submitted == @[offer] + + await subscription.unsubscribe() + + test "sets host address when submitting storage offer": + var offerWithoutHost = offer + offerWithoutHost.host = Address.default + + await token.approve(storage.address, request.maxPrice) + await market.requestStorage(request) + + var submitted: StorageOffer + proc onOffer(offer: StorageOffer) = + submitted = offer + let subscription = await market.subscribeOffers(request.id, onOffer) + + await market.offerStorage(offerWithoutHost) + + check submitted.host == accounts[0]