[market] submit storage offers

This commit is contained in:
Mark Spanbroek 2022-03-29 09:47:49 +02:00 committed by markspanbroek
parent e52153e2ba
commit 9f76e714a2
4 changed files with 102 additions and 22 deletions

View File

@ -20,6 +20,16 @@ func new*(_: type OnChainMarket, contract: Storage): OnChainMarket =
raiseAssert("Storage contract should have a signer") raiseAssert("Storage contract should have a signer")
OnChainMarket(contract: contract, signer: 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, method subscribeRequests(market: OnChainMarket,
callback: OnRequest): callback: OnRequest):
Future[MarketSubscription] {.async.} = Future[MarketSubscription] {.async.} =
@ -28,10 +38,14 @@ method subscribeRequests(market: OnChainMarket,
let subscription = await market.contract.subscribe(StorageRequested, onEvent) let subscription = await market.contract.subscribe(StorageRequested, onEvent)
return OnChainMarketSubscription(eventSubscription: subscription) return OnChainMarketSubscription(eventSubscription: subscription)
method requestStorage(market: OnChainMarket, request: StorageRequest) {.async.} = method subscribeOffers(market: OnChainMarket,
var request = request requestId: array[32, byte],
request.client = await market.signer.getAddress() callback: OnOffer):
await market.contract.requestStorage(request) 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.} = method unsubscribe*(subscription: OnChainMarketSubscription) {.async.} =
await subscription.eventSubscription.unsubscribe() await subscription.eventSubscription.unsubscribe()

View File

@ -1,5 +1,7 @@
import pkg/contractabi import pkg/contractabi
import pkg/nimcrypto import pkg/nimcrypto
import pkg/ethers/fields
import pkg/questionable/results
export contractabi export contractabi
@ -10,19 +12,23 @@ type
price*: UInt256 price*: UInt256
expiry*: UInt256 expiry*: UInt256
func toTuple(offer: StorageOffer): auto = func fromTuple(_: type StorageOffer, tupl: tuple): StorageOffer =
( StorageOffer(
offer.host, host: tupl[0],
offer.requestId, requestId: tupl[1],
offer.price, price: tupl[2],
offer.expiry expiry: tupl[3]
) )
func solidityType*(_: type StorageOffer): string = func solidityType*(_: type StorageOffer): string =
solidityType(typeof StorageOffer.default.toTuple) solidityType(StorageOffer.fieldTypes)
func encode*(encoder: var AbiEncoder, offer: StorageOffer) = 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] = func id*(offer: StorageOffer): array[32, byte] =
let encoding = AbiEncoder.encode(offer) let encoding = AbiEncoder.encode(offer)

View File

@ -6,7 +6,7 @@ import ./requests
import ./offers import ./offers
export stint export stint
export contract export ethers
type type
Storage* = ref object of Contract Storage* = ref object of Contract
@ -14,6 +14,10 @@ type
StorageRequested* = object of Event StorageRequested* = object of Event
requestId*: Id requestId*: Id
request*: StorageRequest request*: StorageRequest
StorageOffered* = object of Event
offerId*: Id
offer*: StorageOffer
requestId* {.indexed.}: Id
proc collateralAmount*(storage: Storage): UInt256 {.contract, view.} proc collateralAmount*(storage: Storage): UInt256 {.contract, view.}
proc slashMisses*(storage: Storage): UInt256 {.contract, view.} proc slashMisses*(storage: Storage): UInt256 {.contract, view.}

View File

@ -1,3 +1,4 @@
import std/times
import ./ethertest import ./ethertest
import dagger/contracts import dagger/contracts
import dagger/contracts/testtoken import dagger/contracts/testtoken
@ -8,14 +9,28 @@ ethersuite "On-Chain Market":
var market: OnChainMarket var market: OnChainMarket
var storage: Storage var storage: Storage
var token: TestToken var token: TestToken
var request: StorageRequest
var offer: StorageOffer
setup: setup:
let deployment = deployment() let deployment = deployment()
storage = Storage.new(!deployment.address(Storage), provider.getSigner()) storage = Storage.new(!deployment.address(Storage), provider.getSigner())
token = TestToken.new(!deployment.address(TestToken), provider.getSigner()) token = TestToken.new(!deployment.address(TestToken), provider.getSigner())
await token.mint(accounts[0], 1000.u256) 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) 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": test "fails to instantiate when contract does not have a signer":
let storageWithoutSigner = storage.connect(provider) let storageWithoutSigner = storage.connect(provider)
expect AssertionError: expect AssertionError:
@ -26,14 +41,55 @@ ethersuite "On-Chain Market":
proc onRequest(request: StorageRequest) = proc onRequest(request: StorageRequest) =
submitted.add(request) submitted.add(request)
let subscription = await market.subscribeRequests(onRequest) let subscription = await market.subscribeRequests(onRequest)
let request = StorageRequest( await token.approve(storage.address, request.maxPrice)
duration: uint16.example.u256,
size: uint32.example.u256,
contentHash: array[32, byte].example
)
await market.requestStorage(request) await market.requestStorage(request)
check submitted.len == 1
check submitted[0].duration == request.duration check submitted == @[request]
check submitted[0].size == request.size
check submitted[0].contentHash == request.contentHash
await subscription.unsubscribe() 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]