diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4fddce10..052b6eb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: run: make -j${ncpu} test - name: Start Ethereum node with Codex contracts - working-directory: vendor/dagger-contracts + working-directory: vendor/codex-contracts-eth run: | if [[ '${{ matrix.os }}' == 'windows' ]]; then export PATH="${PATH}:/c/program files/nodejs" diff --git a/.gitmodules b/.gitmodules index 9abd397f..b74ec86f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -133,10 +133,6 @@ url = https://github.com/status-im/nim-websock.git ignore = untracked branch = master -[submodule "vendor/dagger-contracts"] - path = vendor/dagger-contracts - url = https://github.com/status-im/dagger-contracts - ignore = dirty [submodule "vendor/nim-contract-abi"] path = vendor/nim-contract-abi url = https://github.com/status-im/nim-contract-abi @@ -182,3 +178,6 @@ [submodule "vendor/nim-eth"] path = vendor/nim-eth url = https://github.com/status-im/nim-eth +[submodule "vendor/codex-contracts-eth"] + path = vendor/codex-contracts-eth + url = https://github.com/status-im/codex-contracts-eth diff --git a/BUILDING.md b/BUILDING.md index d97e5400..1c516f6d 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -132,7 +132,7 @@ $ nvm install --lts In that same terminal run ```text -$ cd repos/nim-codex/vendor/dagger-contracts && npm install && npm start +$ cd repos/nim-codex/vendor/codex-contracts-eth && npm install && npm start ``` Those commands install and launch a [Hardhat](https://hardhat.org/) environment with nim-codex's Ethereum contracts. diff --git a/codex/contracts.nim b/codex/contracts.nim index c1c4f7c7..d2cd0c9e 100644 --- a/codex/contracts.nim +++ b/codex/contracts.nim @@ -1,12 +1,12 @@ import contracts/requests -import contracts/storage +import contracts/marketplace import contracts/deployment import contracts/market import contracts/proofs import contracts/interactions export requests -export storage +export marketplace export deployment export market export proofs diff --git a/codex/contracts/Readme.md b/codex/contracts/Readme.md index 6a4ea8d0..b2105075 100644 --- a/codex/contracts/Readme.md +++ b/codex/contracts/Readme.md @@ -20,7 +20,7 @@ import ethers let address = # fill in address where the contract was deployed let provider = JsonRpcProvider.new("ws://localhost:8545") -let storage = Storage.new(address, provider) +let marketplace = Marketplace.new(address, provider) ``` Setup client and host so that they can sign transactions; here we use the first @@ -39,7 +39,7 @@ Hosts need to put up collateral before participating in storage contracts. A host can learn about the amount of collateral that is required: ```nim -let collateralAmount = await storage.collateralAmount() +let collateral = await marketplace.collateral() ``` The host then needs to prepare a payment to the smart contract by calling the @@ -50,7 +50,7 @@ After preparing the payment, the host can deposit collateral: ```nim await storage .connect(host) - .deposit(collateralAmount) + .deposit(collateral) ``` When a host is not participating in storage offers or contracts, it can withdraw @@ -176,6 +176,6 @@ await storage .markProofAsMissing(id, period) ``` -[1]: https://github.com/status-im/dagger-contracts/ +[1]: https://github.com/status-im/codex-contracts-eth/ [2]: https://ethereum.org/en/developers/docs/standards/tokens/erc-20/ [3]: https://github.com/status-im/codex-research/blob/main/design/storage-proof-timing.md diff --git a/codex/contracts/deployment.nim b/codex/contracts/deployment.nim index 2b95a651..3c1357b3 100644 --- a/codex/contracts/deployment.nim +++ b/codex/contracts/deployment.nim @@ -6,7 +6,7 @@ import pkg/questionable type Deployment* = object json: JsonNode -const defaultFile = "vendor" / "dagger-contracts" / "deployment-localhost.json" +const defaultFile = "vendor" / "codex-contracts-eth" / "deployment-localhost.json" ## Reads deployment information from a json file. It expects a file that has ## been exported with Hardhat deploy. diff --git a/codex/contracts/interactions.nim b/codex/contracts/interactions.nim index 5f4dcd9c..4cf16492 100644 --- a/codex/contracts/interactions.nim +++ b/codex/contracts/interactions.nim @@ -4,7 +4,7 @@ import ../purchasing import ../sales import ../proving import ./deployment -import ./storage +import ./marketplace import ./market import ./proofs import ./clock @@ -25,11 +25,11 @@ proc new*(_: type ContractInteractions, signer: Signer, deployment: Deployment): ?ContractInteractions = - without address =? deployment.address(Storage): - error "Unable to determine address of the Storage smart contract" + without address =? deployment.address(Marketplace): + error "Unable to determine address of the Marketplace smart contract" return none ContractInteractions - let contract = Storage.new(address, signer) + let contract = Marketplace.new(address, signer) let market = OnChainMarket.new(contract) let proofs = OnChainProofs.new(contract) let clock = OnChainClock.new(signer.provider) diff --git a/codex/contracts/market.nim b/codex/contracts/market.nim index 2ed4148f..69dab2cf 100644 --- a/codex/contracts/market.nim +++ b/codex/contracts/market.nim @@ -4,22 +4,22 @@ import pkg/ethers/testing import pkg/upraises import pkg/questionable import ../market -import ./storage +import ./marketplace export market type OnChainMarket* = ref object of Market - contract: Storage + contract: Marketplace signer: Signer MarketSubscription = market.Subscription EventSubscription = ethers.Subscription OnChainMarketSubscription = ref object of MarketSubscription eventSubscription: EventSubscription -func new*(_: type OnChainMarket, contract: Storage): OnChainMarket = +func new*(_: type OnChainMarket, contract: Marketplace): OnChainMarket = without signer =? contract.signer: - raiseAssert("Storage contract should have a signer") + raiseAssert("Marketplace contract should have a signer") OnChainMarket( contract: contract, signer: signer, diff --git a/codex/contracts/marketplace.nim b/codex/contracts/marketplace.nim new file mode 100644 index 00000000..db00aeaa --- /dev/null +++ b/codex/contracts/marketplace.nim @@ -0,0 +1,62 @@ +import pkg/ethers +import pkg/json_rpc/rpcclient +import pkg/stint +import pkg/chronos +import ../clock +import ./requests + +export stint +export ethers + +type + Marketplace* = ref object of Contract + StorageRequested* = object of Event + requestId*: RequestId + ask*: StorageAsk + SlotFilled* = object of Event + requestId* {.indexed.}: RequestId + slotIndex* {.indexed.}: UInt256 + slotId*: SlotId + RequestFulfilled* = object of Event + requestId* {.indexed.}: RequestId + RequestCancelled* = object of Event + requestId* {.indexed.}: RequestId + RequestFailed* = object of Event + requestId* {.indexed.}: RequestId + ProofSubmitted* = object of Event + id*: SlotId + proof*: seq[byte] + + +proc collateral*(marketplace: Marketplace): UInt256 {.contract, view.} +proc slashMisses*(marketplace: Marketplace): UInt256 {.contract, view.} +proc slashPercentage*(marketplace: Marketplace): UInt256 {.contract, view.} +proc minCollateralThreshold*(marketplace: Marketplace): UInt256 {.contract, view.} + +proc deposit*(marketplace: Marketplace, amount: UInt256) {.contract.} +proc withdraw*(marketplace: Marketplace) {.contract.} +proc balanceOf*(marketplace: Marketplace, account: Address): UInt256 {.contract, view.} + +proc requestStorage*(marketplace: Marketplace, request: StorageRequest) {.contract.} +proc fillSlot*(marketplace: Marketplace, requestId: RequestId, slotIndex: UInt256, proof: seq[byte]) {.contract.} +proc withdrawFunds*(marketplace: Marketplace, requestId: RequestId) {.contract.} +proc freeSlot*(marketplace: Marketplace, id: SlotId) {.contract.} +proc getRequest*(marketplace: Marketplace, id: RequestId): StorageRequest {.contract, view.} +proc getHost*(marketplace: Marketplace, id: SlotId): Address {.contract, view.} + +proc myRequests*(marketplace: Marketplace): seq[RequestId] {.contract, view.} +proc state*(marketplace: Marketplace, requestId: RequestId): RequestState {.contract, view.} +proc requestEnd*(marketplace: Marketplace, requestId: RequestId): SecondsSince1970 {.contract, view.} + +proc proofPeriod*(marketplace: Marketplace): UInt256 {.contract, view.} +proc proofTimeout*(marketplace: Marketplace): UInt256 {.contract, view.} + +proc proofEnd*(marketplace: Marketplace, id: SlotId): UInt256 {.contract, view.} +proc missingProofs*(marketplace: Marketplace, id: SlotId): UInt256 {.contract, view.} +proc isProofRequired*(marketplace: Marketplace, id: SlotId): bool {.contract, view.} +proc willProofBeRequired*(marketplace: Marketplace, id: SlotId): bool {.contract, view.} +proc getChallenge*(marketplace: Marketplace, id: SlotId): array[32, byte] {.contract, view.} +proc getPointer*(marketplace: Marketplace, id: SlotId): uint8 {.contract, view.} + +proc submitProof*(marketplace: Marketplace, id: SlotId, proof: seq[byte]) {.contract.} +proc markProofAsMissing*(marketplace: Marketplace, id: SlotId, period: UInt256) {.contract.} diff --git a/codex/contracts/proofs.nim b/codex/contracts/proofs.nim index f67073a1..f5ce5c69 100644 --- a/codex/contracts/proofs.nim +++ b/codex/contracts/proofs.nim @@ -2,13 +2,13 @@ import std/strutils import pkg/ethers import pkg/ethers/testing import ../storageproofs/timing/proofs -import ./storage +import ./marketplace export proofs type OnChainProofs* = ref object of Proofs - storage: Storage + marketplace: Marketplace pollInterval*: Duration ProofsSubscription = proofs.Subscription EventSubscription = ethers.Subscription @@ -17,17 +17,17 @@ type const DefaultPollInterval = 3.seconds -proc new*(_: type OnChainProofs, storage: Storage): OnChainProofs = - OnChainProofs(storage: storage, pollInterval: DefaultPollInterval) +proc new*(_: type OnChainProofs, marketplace: Marketplace): OnChainProofs = + OnChainProofs(marketplace: marketplace, pollInterval: DefaultPollInterval) method periodicity*(proofs: OnChainProofs): Future[Periodicity] {.async.} = - let period = await proofs.storage.proofPeriod() + let period = await proofs.marketplace.proofPeriod() return Periodicity(seconds: period) method isProofRequired*(proofs: OnChainProofs, id: SlotId): Future[bool] {.async.} = try: - return await proofs.storage.isProofRequired(id) + return await proofs.marketplace.isProofRequired(id) except ProviderError as e: if e.revertReason.contains("Slot empty"): return false @@ -36,7 +36,7 @@ method isProofRequired*(proofs: OnChainProofs, method willProofBeRequired*(proofs: OnChainProofs, id: SlotId): Future[bool] {.async.} = try: - return await proofs.storage.willProofBeRequired(id) + return await proofs.marketplace.willProofBeRequired(id) except ProviderError as e: if e.revertReason.contains("Slot empty"): return false @@ -45,7 +45,7 @@ method willProofBeRequired*(proofs: OnChainProofs, method getProofEnd*(proofs: OnChainProofs, id: SlotId): Future[UInt256] {.async.} = try: - return await proofs.storage.proofEnd(id) + return await proofs.marketplace.proofEnd(id) except ProviderError as e: if e.revertReason.contains("Slot empty"): return 0.u256 @@ -54,14 +54,14 @@ method getProofEnd*(proofs: OnChainProofs, method submitProof*(proofs: OnChainProofs, id: SlotId, proof: seq[byte]) {.async.} = - await proofs.storage.submitProof(id, proof) + await proofs.marketplace.submitProof(id, proof) method subscribeProofSubmission*(proofs: OnChainProofs, callback: OnProofSubmitted): Future[ProofsSubscription] {.async.} = proc onEvent(event: ProofSubmitted) {.upraises: [].} = callback(event.id, event.proof) - let subscription = await proofs.storage.subscribe(ProofSubmitted, onEvent) + let subscription = await proofs.marketplace.subscribe(ProofSubmitted, onEvent) return OnChainProofsSubscription(eventSubscription: subscription) method unsubscribe*(subscription: OnChainProofsSubscription) {.async, upraises:[].} = diff --git a/codex/contracts/storage.nim b/codex/contracts/storage.nim deleted file mode 100644 index b83a4988..00000000 --- a/codex/contracts/storage.nim +++ /dev/null @@ -1,62 +0,0 @@ -import pkg/ethers -import pkg/json_rpc/rpcclient -import pkg/stint -import pkg/chronos -import ../clock -import ./requests - -export stint -export ethers - -type - Storage* = ref object of Contract - StorageRequested* = object of Event - requestId*: RequestId - ask*: StorageAsk - SlotFilled* = object of Event - requestId* {.indexed.}: RequestId - slotIndex* {.indexed.}: UInt256 - slotId*: SlotId - RequestFulfilled* = object of Event - requestId* {.indexed.}: RequestId - RequestCancelled* = object of Event - requestId* {.indexed.}: RequestId - RequestFailed* = object of Event - requestId* {.indexed.}: RequestId - ProofSubmitted* = object of Event - id*: SlotId - proof*: seq[byte] - - -proc collateralAmount*(storage: Storage): UInt256 {.contract, view.} -proc slashMisses*(storage: Storage): UInt256 {.contract, view.} -proc slashPercentage*(storage: Storage): UInt256 {.contract, view.} -proc minCollateralThreshold*(storage: Storage): UInt256 {.contract, view.} - -proc deposit*(storage: Storage, amount: UInt256) {.contract.} -proc withdraw*(storage: Storage) {.contract.} -proc balanceOf*(storage: Storage, account: Address): UInt256 {.contract, view.} - -proc requestStorage*(storage: Storage, request: StorageRequest) {.contract.} -proc fillSlot*(storage: Storage, requestId: RequestId, slotIndex: UInt256, proof: seq[byte]) {.contract.} -proc withdrawFunds*(storage: Storage, requestId: RequestId) {.contract.} -proc payoutSlot*(storage: Storage, requestId: RequestId, slotIndex: UInt256) {.contract.} -proc getRequest*(storage: Storage, id: RequestId): StorageRequest {.contract, view.} -proc getHost*(storage: Storage, id: SlotId): Address {.contract, view.} - -proc myRequests*(storage: Storage): seq[RequestId] {.contract, view.} -proc state*(storage: Storage, requestId: RequestId): RequestState {.contract, view.} -proc requestEnd*(storage: Storage, requestId: RequestId): SecondsSince1970 {.contract, view.} - -proc proofPeriod*(storage: Storage): UInt256 {.contract, view.} -proc proofTimeout*(storage: Storage): UInt256 {.contract, view.} - -proc proofEnd*(storage: Storage, id: SlotId): UInt256 {.contract, view.} -proc missingProofs*(storage: Storage, id: SlotId): UInt256 {.contract, view.} -proc isProofRequired*(storage: Storage, id: SlotId): bool {.contract, view.} -proc willProofBeRequired*(storage: Storage, id: SlotId): bool {.contract, view.} -proc getChallenge*(storage: Storage, id: SlotId): array[32, byte] {.contract, view.} -proc getPointer*(storage: Storage, id: SlotId): uint8 {.contract, view.} - -proc submitProof*(storage: Storage, id: SlotId, proof: seq[byte]) {.contract.} -proc markProofAsMissing*(storage: Storage, id: SlotId, period: UInt256) {.contract.} diff --git a/tests/contracts/testCollateral.nim b/tests/contracts/testCollateral.nim index 6d2079b8..2fef14f9 100644 --- a/tests/contracts/testCollateral.nim +++ b/tests/contracts/testCollateral.nim @@ -6,27 +6,27 @@ import ../ethertest ethersuite "Collateral": - let collateralAmount = 100.u256 + let collateral = 100.u256 - var storage: Storage + var marketplace: Marketplace var token: TestToken setup: let deployment = deployment() - storage = Storage.new(!deployment.address(Storage), provider.getSigner()) + marketplace = Marketplace.new(!deployment.address(Marketplace), provider.getSigner()) token = TestToken.new(!deployment.address(TestToken), provider.getSigner()) await token.mint(accounts[0], 1000.u256) test "increases collateral": - await token.approve(storage.address, collateralAmount) - await storage.deposit(collateralAmount) - let collateral = await storage.balanceOf(accounts[0]) - check collateral == collateralAmount + await token.approve(marketplace.address, collateral) + await marketplace.deposit(collateral) + let balance = await marketplace.balanceOf(accounts[0]) + check balance == collateral test "withdraws collateral": - await token.approve(storage.address, collateralAmount) - await storage.deposit(collateralAmount) + await token.approve(marketplace.address, collateral) + await marketplace.deposit(collateral) let balanceBefore = await token.balanceOf(accounts[0]) - await storage.withdraw() + await marketplace.withdraw() let balanceAfter = await token.balanceOf(accounts[0]) - check (balanceAfter - balanceBefore) == collateralAmount + check (balanceAfter - balanceBefore) == collateral diff --git a/tests/contracts/testContracts.nim b/tests/contracts/testContracts.nim index 3063b899..d8c77a5d 100644 --- a/tests/contracts/testContracts.nim +++ b/tests/contracts/testContracts.nim @@ -8,19 +8,19 @@ import ../ethertest import ./examples import ./time -ethersuite "Storage contracts": +ethersuite "Marketplace contracts": let proof = exampleProof() var client, host: Signer - var storage: Storage + var marketplace: Marketplace var token: TestToken - var collateralAmount: UInt256 + var collateral: UInt256 var periodicity: Periodicity var request: StorageRequest var slotId: SlotId proc switchAccount(account: Signer) = - storage = storage.connect(account) + marketplace = marketplace.connect(account) token = token.connect(account) setup: @@ -28,44 +28,44 @@ ethersuite "Storage contracts": host = provider.getSigner(accounts[1]) let deployment = deployment() - storage = Storage.new(!deployment.address(Storage), provider.getSigner()) + marketplace = Marketplace.new(!deployment.address(Marketplace), provider.getSigner()) token = TestToken.new(!deployment.address(TestToken), provider.getSigner()) await token.mint(await client.getAddress(), 1_000_000_000.u256) await token.mint(await host.getAddress(), 1000_000_000.u256) - collateralAmount = await storage.collateralAmount() - periodicity = Periodicity(seconds: await storage.proofPeriod()) + collateral = await marketplace.collateral() + periodicity = Periodicity(seconds: await marketplace.proofPeriod()) request = StorageRequest.example request.client = await client.getAddress() switchAccount(client) - await token.approve(storage.address, request.price) - await storage.requestStorage(request) + await token.approve(marketplace.address, request.price) + await marketplace.requestStorage(request) switchAccount(host) - await token.approve(storage.address, collateralAmount) - await storage.deposit(collateralAmount) - await storage.fillSlot(request.id, 0.u256, proof) + await token.approve(marketplace.address, collateral) + await marketplace.deposit(collateral) + await marketplace.fillSlot(request.id, 0.u256, proof) slotId = request.slotId(0.u256) 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 marketplace.isProofRequired(slotId)) and + (await marketplace.getPointer(slotId)) < 250 ): await provider.advanceTime(periodicity.seconds) proc startContract() {.async.} = for slotIndex in 1..