diff --git a/codex/contracts/market.nim b/codex/contracts/market.nim index c2b89a86..dba46163 100644 --- a/codex/contracts/market.nim +++ b/codex/contracts/market.nim @@ -2,9 +2,9 @@ import std/sequtils import std/strutils import std/sugar import pkg/ethers -import pkg/ethers/testing import pkg/upraises import pkg/questionable +import ../utils/exceptions import ../logutils import ../market import ./marketplace @@ -32,147 +32,177 @@ func new*(_: type OnChainMarket, contract: Marketplace): OnChainMarket = signer: signer, ) +proc raiseMarketError(message: string) {.raises: [MarketError].} = + raise newException(MarketError, message) + +template convertEthersError(body) = + try: + body + except EthersError as error: + raiseMarketError(error.msgDetail) + proc approveFunds(market: OnChainMarket, amount: UInt256) {.async.} = debug "Approving tokens", amount - let tokenAddress = await market.contract.token() - let token = Erc20Token.new(tokenAddress, market.signer) - - discard await token.increaseAllowance(market.contract.address(), amount).confirm(1) + convertEthersError: + let tokenAddress = await market.contract.token() + let token = Erc20Token.new(tokenAddress, market.signer) + discard await token.increaseAllowance(market.contract.address(), amount).confirm(1) method getZkeyHash*(market: OnChainMarket): Future[?string] {.async.} = let config = await market.contract.config() return some config.proofs.zkeyHash method getSigner*(market: OnChainMarket): Future[Address] {.async.} = - return await market.signer.getAddress() + convertEthersError: + return await market.signer.getAddress() method periodicity*(market: OnChainMarket): Future[Periodicity] {.async.} = - let config = await market.contract.config() - let period = config.proofs.period - return Periodicity(seconds: period) + convertEthersError: + let config = await market.contract.config() + let period = config.proofs.period + return Periodicity(seconds: period) method proofTimeout*(market: OnChainMarket): Future[UInt256] {.async.} = - let config = await market.contract.config() - return config.proofs.timeout + convertEthersError: + let config = await market.contract.config() + return config.proofs.timeout method proofDowntime*(market: OnChainMarket): Future[uint8] {.async.} = - let config = await market.contract.config() - return config.proofs.downtime + convertEthersError: + let config = await market.contract.config() + return config.proofs.downtime method getPointer*(market: OnChainMarket, slotId: SlotId): Future[uint8] {.async.} = - let overrides = CallOverrides(blockTag: some BlockTag.pending) - return await market.contract.getPointer(slotId, overrides) + convertEthersError: + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.getPointer(slotId, overrides) method myRequests*(market: OnChainMarket): Future[seq[RequestId]] {.async.} = - return await market.contract.myRequests + convertEthersError: + return await market.contract.myRequests method mySlots*(market: OnChainMarket): Future[seq[SlotId]] {.async.} = - let slots = await market.contract.mySlots() - debug "Fetched my slots", numSlots=len(slots) + convertEthersError: + let slots = await market.contract.mySlots() + debug "Fetched my slots", numSlots=len(slots) - return slots + return slots method requestStorage(market: OnChainMarket, request: StorageRequest){.async.} = - debug "Requesting storage" - await market.approveFunds(request.price()) - await market.contract.requestStorage(request) + convertEthersError: + debug "Requesting storage" + await market.approveFunds(request.price()) + await market.contract.requestStorage(request) method getRequest(market: OnChainMarket, id: RequestId): Future[?StorageRequest] {.async.} = - try: - return some await market.contract.getRequest(id) - except ProviderError as e: - if e.revertReason.contains("Unknown request"): - return none StorageRequest - raise e + convertEthersError: + try: + return some await market.contract.getRequest(id) + except ProviderError as e: + if e.msgDetail.contains("Unknown request"): + return none StorageRequest + raise e method requestState*(market: OnChainMarket, requestId: RequestId): Future[?RequestState] {.async.} = - try: - let overrides = CallOverrides(blockTag: some BlockTag.pending) - return some await market.contract.requestState(requestId, overrides) - except ProviderError as e: - if e.revertReason.contains("Unknown request"): - return none RequestState - raise e + convertEthersError: + try: + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return some await market.contract.requestState(requestId, overrides) + except ProviderError as e: + if e.msgDetail.contains("Unknown request"): + return none RequestState + raise e method slotState*(market: OnChainMarket, slotId: SlotId): Future[SlotState] {.async.} = - let overrides = CallOverrides(blockTag: some BlockTag.pending) - return await market.contract.slotState(slotId, overrides) + convertEthersError: + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.slotState(slotId, overrides) method getRequestEnd*(market: OnChainMarket, id: RequestId): Future[SecondsSince1970] {.async.} = - return await market.contract.requestEnd(id) + convertEthersError: + return await market.contract.requestEnd(id) method getHost(market: OnChainMarket, requestId: RequestId, slotIndex: UInt256): Future[?Address] {.async.} = - let slotId = slotId(requestId, slotIndex) - let address = await market.contract.getHost(slotId) - if address != Address.default: - return some address - else: - return none Address + convertEthersError: + let slotId = slotId(requestId, slotIndex) + let address = await market.contract.getHost(slotId) + if address != Address.default: + return some address + else: + return none Address method getActiveSlot*(market: OnChainMarket, slotId: SlotId): Future[?Slot] {.async.} = - - try: - return some await market.contract.getActiveSlot(slotId) - except ProviderError as e: - if e.revertReason.contains("Slot is free"): - return none Slot - raise e + convertEthersError: + try: + return some await market.contract.getActiveSlot(slotId) + except ProviderError as e: + if e.msgDetail.contains("Slot is free"): + return none Slot + raise e method fillSlot(market: OnChainMarket, requestId: RequestId, slotIndex: UInt256, proof: Groth16Proof, collateral: UInt256) {.async.} = - await market.approveFunds(collateral) - await market.contract.fillSlot(requestId, slotIndex, proof) + convertEthersError: + await market.approveFunds(collateral) + await market.contract.fillSlot(requestId, slotIndex, proof) method freeSlot*(market: OnChainMarket, slotId: SlotId) {.async.} = - await market.contract.freeSlot(slotId) + convertEthersError: + await market.contract.freeSlot(slotId) method withdrawFunds(market: OnChainMarket, requestId: RequestId) {.async.} = - await market.contract.withdrawFunds(requestId) + convertEthersError: + await market.contract.withdrawFunds(requestId) method isProofRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.async.} = - try: - let overrides = CallOverrides(blockTag: some BlockTag.pending) - return await market.contract.isProofRequired(id, overrides) - except ProviderError as e: - if e.revertReason.contains("Slot is free"): - return false - raise e + convertEthersError: + try: + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.isProofRequired(id, overrides) + except ProviderError as e: + if e.msgDetail.contains("Slot is free"): + return false + raise e method willProofBeRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.async.} = - try: - let overrides = CallOverrides(blockTag: some BlockTag.pending) - return await market.contract.willProofBeRequired(id, overrides) - except ProviderError as e: - if e.revertReason.contains("Slot is free"): - return false - raise e + convertEthersError: + try: + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.willProofBeRequired(id, overrides) + except ProviderError as e: + if e.msgDetail.contains("Slot is free"): + return false + raise e method getChallenge*(market: OnChainMarket, id: SlotId): Future[ProofChallenge] {.async.} = - let overrides = CallOverrides(blockTag: some BlockTag.pending) - return await market.contract.getChallenge(id, overrides) + convertEthersError: + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.getChallenge(id, overrides) method submitProof*(market: OnChainMarket, id: SlotId, proof: Groth16Proof) {.async.} = - await market.contract.submitProof(id, proof) + convertEthersError: + await market.contract.submitProof(id, proof) method markProofAsMissing*(market: OnChainMarket, id: SlotId, period: Period) {.async.} = - await market.contract.markProofAsMissing(id, period) + convertEthersError: + await market.contract.markProofAsMissing(id, period) method canProofBeMarkedAsMissing*( market: OnChainMarket, @@ -186,7 +216,7 @@ method canProofBeMarkedAsMissing*( await contractWithoutSigner.markProofAsMissing(id, period, overrides) return true except EthersError as e: - trace "Proof can not be marked as missing", msg = e.msg + trace "Proof cannot be marked as missing", msg = e.msg return false method subscribeRequests*(market: OnChainMarket, @@ -196,16 +226,20 @@ method subscribeRequests*(market: OnChainMarket, callback(event.requestId, event.ask, event.expiry) - let subscription = await market.contract.subscribe(StorageRequested, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(StorageRequested, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeSlotFilled*(market: OnChainMarket, callback: OnSlotFilled): Future[MarketSubscription] {.async.} = proc onEvent(event: SlotFilled) {.upraises:[].} = callback(event.requestId, event.slotIndex) - let subscription = await market.contract.subscribe(SlotFilled, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(SlotFilled, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeSlotFilled*(market: OnChainMarket, requestId: RequestId, @@ -215,23 +249,29 @@ method subscribeSlotFilled*(market: OnChainMarket, proc onSlotFilled(eventRequestId: RequestId, eventSlotIndex: UInt256) = if eventRequestId == requestId and eventSlotIndex == slotIndex: callback(requestId, slotIndex) - return await market.subscribeSlotFilled(onSlotFilled) + + convertEthersError: + return await market.subscribeSlotFilled(onSlotFilled) method subscribeSlotFreed*(market: OnChainMarket, callback: OnSlotFreed): Future[MarketSubscription] {.async.} = proc onEvent(event: SlotFreed) {.upraises:[].} = callback(event.requestId, event.slotIndex) - let subscription = await market.contract.subscribe(SlotFreed, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(SlotFreed, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeFulfillment(market: OnChainMarket, callback: OnFulfillment): Future[MarketSubscription] {.async.} = proc onEvent(event: RequestFulfilled) {.upraises:[].} = callback(event.requestId) - let subscription = await market.contract.subscribe(RequestFulfilled, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(RequestFulfilled, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeFulfillment(market: OnChainMarket, requestId: RequestId, @@ -240,16 +280,20 @@ method subscribeFulfillment(market: OnChainMarket, proc onEvent(event: RequestFulfilled) {.upraises:[].} = if event.requestId == requestId: callback(event.requestId) - let subscription = await market.contract.subscribe(RequestFulfilled, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(RequestFulfilled, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeRequestCancelled*(market: OnChainMarket, callback: OnRequestCancelled): Future[MarketSubscription] {.async.} = proc onEvent(event: RequestCancelled) {.upraises:[].} = callback(event.requestId) - let subscription = await market.contract.subscribe(RequestCancelled, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(RequestCancelled, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeRequestCancelled*(market: OnChainMarket, requestId: RequestId, @@ -258,16 +302,20 @@ method subscribeRequestCancelled*(market: OnChainMarket, proc onEvent(event: RequestCancelled) {.upraises:[].} = if event.requestId == requestId: callback(event.requestId) - let subscription = await market.contract.subscribe(RequestCancelled, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(RequestCancelled, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeRequestFailed*(market: OnChainMarket, callback: OnRequestFailed): Future[MarketSubscription] {.async.} = proc onEvent(event: RequestFailed) {.upraises:[]} = callback(event.requestId) - let subscription = await market.contract.subscribe(RequestFailed, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(RequestFailed, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeRequestFailed*(market: OnChainMarket, requestId: RequestId, @@ -276,16 +324,20 @@ method subscribeRequestFailed*(market: OnChainMarket, proc onEvent(event: RequestFailed) {.upraises:[]} = if event.requestId == requestId: callback(event.requestId) - let subscription = await market.contract.subscribe(RequestFailed, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(RequestFailed, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method subscribeProofSubmission*(market: OnChainMarket, callback: OnProofSubmitted): Future[MarketSubscription] {.async.} = proc onEvent(event: ProofSubmitted) {.upraises: [].} = callback(event.id) - let subscription = await market.contract.subscribe(ProofSubmitted, onEvent) - return OnChainMarketSubscription(eventSubscription: subscription) + + convertEthersError: + let subscription = await market.contract.subscribe(ProofSubmitted, onEvent) + return OnChainMarketSubscription(eventSubscription: subscription) method unsubscribe*(subscription: OnChainMarketSubscription) {.async.} = await subscription.eventSubscription.unsubscribe() @@ -293,20 +345,20 @@ method unsubscribe*(subscription: OnChainMarketSubscription) {.async.} = method queryPastStorageRequests*(market: OnChainMarket, blocksAgo: int): Future[seq[PastStorageRequest]] {.async.} = + convertEthersError: + let contract = market.contract + let provider = contract.provider - let contract = market.contract - let provider = contract.provider + let head = await provider.getBlockNumber() + let fromBlock = BlockTag.init(head - blocksAgo.abs.u256) - let head = await provider.getBlockNumber() - let fromBlock = BlockTag.init(head - blocksAgo.abs.u256) - - let events = await contract.queryFilter(StorageRequested, - fromBlock, - BlockTag.latest) - return events.map(event => - PastStorageRequest( - requestId: event.requestId, - ask: event.ask, - expiry: event.expiry + let events = await contract.queryFilter(StorageRequested, + fromBlock, + BlockTag.latest) + return events.map(event => + PastStorageRequest( + requestId: event.requestId, + ask: event.ask, + expiry: event.expiry + ) ) - ) diff --git a/codex/market.nim b/codex/market.nim index acb0cfe3..76befc75 100644 --- a/codex/market.nim +++ b/codex/market.nim @@ -5,6 +5,7 @@ import pkg/ethers/erc20 import ./contracts/requests import ./contracts/proofs import ./clock +import ./errors import ./periods export chronos @@ -16,6 +17,7 @@ export periods type Market* = ref object of RootObj + MarketError* = object of CodexError Subscription* = ref object of RootObj OnRequest* = proc(id: RequestId, ask: StorageAsk, diff --git a/codex/sales/states/provingsimulated.nim b/codex/sales/states/provingsimulated.nim index ac2271dd..0b6b5b36 100644 --- a/codex/sales/states/provingsimulated.nim +++ b/codex/sales/states/provingsimulated.nim @@ -33,8 +33,8 @@ when codex_enable_proof_failures: try: warn "Submitting INVALID proof", period = currentPeriod, slotId = slot.id await market.submitProof(slot.id, Groth16Proof.default) - except SignerError as e: - if not e.msgDetail.contains("Invalid proof"): + except MarketError as e: + if not e.msg.contains("Invalid proof"): onSubmitProofError(e, currentPeriod, slot.id) except CatchableError as e: onSubmitProofError(e, currentPeriod, slot.id)