diff --git a/contracts/Contracts.sol b/contracts/Contracts.sol deleted file mode 100644 index 515c2fd..0000000 --- a/contracts/Contracts.sol +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -contract Contracts { - mapping(bytes32 => bool) private ids; // contract id, equal to hash of bid - mapping(bytes32 => uint256) private durations; // contract duration in blocks - mapping(bytes32 => uint256) private sizes; // storage size in bytes - mapping(bytes32 => bytes32) private contentHashes; // hash of data to be stored - mapping(bytes32 => uint256) private proofPeriods; // period between proofs - mapping(bytes32 => uint256) private proofTimeouts; // timeout for proof submission - mapping(bytes32 => uint256) private prices; // price in coins - mapping(bytes32 => address) private hosts; // host that provides storage - - function _duration(bytes32 id) internal view returns (uint256) { - return durations[id]; - } - - function _size(bytes32 id) internal view returns (uint256) { - return sizes[id]; - } - - function _contentHash(bytes32 id) internal view returns (bytes32) { - return contentHashes[id]; - } - - function _proofPeriod(bytes32 id) internal view returns (uint256) { - return proofPeriods[id]; - } - - function _proofTimeout(bytes32 id) internal view returns (uint256) { - return proofTimeouts[id]; - } - - function _price(bytes32 id) internal view returns (uint256) { - return prices[id]; - } - - function _host(bytes32 id) internal view returns (address) { - return hosts[id]; - } - - function _newContract( - uint256 duration, - uint256 size, - bytes32 contentHash, - uint256 proofPeriod, - uint256 proofTimeout, - bytes32 nonce, - uint256 price, - address host, - uint256 bidExpiry, - bytes memory requestSignature, - bytes memory bidSignature - ) internal returns (bytes32 id) { - bytes32 requestHash = _hashRequest( - duration, - size, - contentHash, - proofPeriod, - proofTimeout, - nonce - ); - bytes32 bidHash = _hashBid(requestHash, bidExpiry, price); - _checkSignature(requestSignature, requestHash, msg.sender); - _checkSignature(bidSignature, bidHash, host); - _checkBidExpiry(bidExpiry); - _checkId(bidHash); - id = bidHash; - ids[id] = true; - durations[id] = duration; - sizes[id] = size; - contentHashes[id] = contentHash; - proofPeriods[id] = proofPeriod; - proofTimeouts[id] = proofTimeout; - prices[id] = price; - hosts[id] = host; - } - - // Creates hash for a storage request that can be used to check its signature. - function _hashRequest( - uint256 duration, - uint256 size, - bytes32 hash, - uint256 proofPeriod, - uint256 proofTimeout, - bytes32 nonce - ) internal pure returns (bytes32) { - return - keccak256( - abi.encode( - "[dagger.request.v1]", - duration, - size, - hash, - proofPeriod, - proofTimeout, - nonce - ) - ); - } - - // Creates hash for a storage bid that can be used to check its signature. - function _hashBid( - bytes32 requestHash, - uint256 expiry, - uint256 price - ) internal pure returns (bytes32) { - return keccak256(abi.encode("[dagger.bid.v1]", requestHash, expiry, price)); - } - - // Checks a signature for a storage request or bid, given its hash. - function _checkSignature( - bytes memory signature, - bytes32 hash, - address signer - ) private pure { - bytes32 messageHash = ECDSA.toEthSignedMessageHash(hash); - address recovered = ECDSA.recover(messageHash, signature); - require(recovered == signer, "Invalid signature"); - } - - function _checkBidExpiry(uint256 expiry) private view { - // solhint-disable-next-line not-rely-on-time - require(expiry > block.timestamp, "Bid expired"); - } - - function _checkId(bytes32 id) private view { - require(!ids[id], "Contract already exists"); - } -} diff --git a/contracts/Marketplace.sol b/contracts/Marketplace.sol index 669383c..b477db9 100644 --- a/contracts/Marketplace.sol +++ b/contracts/Marketplace.sol @@ -85,6 +85,14 @@ contract Marketplace is Collateral { emit OfferSelected(id, offer.requestId); } + function _request(bytes32 id) internal view returns (Request storage) { + return requests[id]; + } + + function _offer(bytes32 id) internal view returns (Offer storage) { + return offers[id]; + } + struct Request { address client; uint256 duration; diff --git a/contracts/Storage.sol b/contracts/Storage.sol index bc73605..e5b2ef7 100644 --- a/contracts/Storage.sol +++ b/contracts/Storage.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./Contracts.sol"; +import "./Marketplace.sol"; import "./Proofs.sol"; import "./Collateral.sol"; -contract Storage is Contracts, Proofs, Collateral { +contract Storage is Collateral, Marketplace, Proofs { uint256 public collateralAmount; uint256 public slashMisses; uint256 public slashPercentage; @@ -17,96 +17,30 @@ contract Storage is Contracts, Proofs, Collateral { uint256 _collateralAmount, uint256 _slashMisses, uint256 _slashPercentage - ) Collateral(token) { + ) Marketplace(token, _collateralAmount) { collateralAmount = _collateralAmount; slashMisses = _slashMisses; slashPercentage = _slashPercentage; } - function newContract( - uint256 _duration, - uint256 _size, - bytes32 _contentHash, - uint256 _proofPeriod, - uint256 _proofTimeout, - bytes32 _nonce, - uint256 _price, - address _host, - uint256 _bidExpiry, - bytes memory requestSignature, - bytes memory bidSignature - ) public { - require(balanceOf(_host) >= collateralAmount, "Insufficient collateral"); - bytes32 requestHash = _hashRequest( - _duration, - _size, - _contentHash, - _proofPeriod, - _proofTimeout, - _nonce + function startContract(bytes32 id) public { + Offer storage offer = _offer(id); + require(msg.sender == offer.host, "Only host can call this function"); + Request storage request = _request(offer.requestId); + _expectProofs( + id, + request.proofPeriod, + request.proofTimeout, + request.duration ); - bytes32 bidHash = _hashBid(requestHash, _bidExpiry, _price); - _createLock(bidHash, _bidExpiry); - _lock(_host, bidHash); - token.transferFrom(msg.sender, address(this), _price); - _newContract( - _duration, - _size, - _contentHash, - _proofPeriod, - _proofTimeout, - _nonce, - _price, - _host, - _bidExpiry, - requestSignature, - bidSignature - ); - } - - modifier onlyHost(bytes32 id) { - require(msg.sender == host(id), "Only host can call this function"); - _; - } - - function startContract(bytes32 id) public onlyHost(id) { - _expectProofs(id, proofPeriod(id), proofTimeout(id), duration(id)); } function finishContract(bytes32 id) public { require(block.number > proofEnd(id), "Contract has not ended yet"); require(!finished[id], "Contract already finished"); - _unlock(id); finished[id] = true; - require(token.transfer(host(id), price(id)), "Payment failed"); - } - - function duration(bytes32 contractId) public view returns (uint256) { - return _duration(contractId); - } - - function size(bytes32 contractId) public view returns (uint256) { - return _size(contractId); - } - - function contentHash(bytes32 contractId) public view returns (bytes32) { - return _contentHash(contractId); - } - - function price(bytes32 contractId) public view returns (uint256) { - return _price(contractId); - } - - function host(bytes32 contractId) public view returns (address) { - return _host(contractId); - } - - function proofPeriod(bytes32 contractId) public view returns (uint256) { - return _proofPeriod(contractId); - } - - function proofTimeout(bytes32 contractId) public view returns (uint256) { - return _proofTimeout(contractId); + Offer storage offer = _offer(id); + require(token.transfer(offer.host, offer.price), "Payment failed"); } function proofEnd(bytes32 contractId) public view returns (uint256) { @@ -144,7 +78,8 @@ contract Storage is Contracts, Proofs, Collateral { function markProofAsMissing(bytes32 contractId, uint256 blocknumber) public { _markProofAsMissing(contractId, blocknumber); if (_missed(contractId) % slashMisses == 0) { - _slash(host(contractId), slashPercentage); + Offer storage offer = _offer(contractId); + _slash(offer.host, slashPercentage); } } } diff --git a/contracts/TestContracts.sol b/contracts/TestContracts.sol deleted file mode 100644 index 88cfd2a..0000000 --- a/contracts/TestContracts.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "./Contracts.sol"; - -// exposes internal functions of Contracts for testing -contract TestContracts is Contracts { - function newContract( - uint256 _duration, - uint256 _size, - bytes32 _contentHash, - uint256 _proofPeriod, - uint256 _proofTimeout, - bytes32 _nonce, - uint256 _price, - address _host, - uint256 _bidExpiry, - bytes memory requestSignature, - bytes memory bidSignature - ) public { - _newContract( - _duration, - _size, - _contentHash, - _proofPeriod, - _proofTimeout, - _nonce, - _price, - _host, - _bidExpiry, - requestSignature, - bidSignature - ); - } - - function duration(bytes32 id) public view returns (uint256) { - return _duration(id); - } - - function size(bytes32 id) public view returns (uint256) { - return _size(id); - } - - function contentHash(bytes32 id) public view returns (bytes32) { - return _contentHash(id); - } - - function price(bytes32 id) public view returns (uint256) { - return _price(id); - } - - function host(bytes32 id) public view returns (address) { - return _host(id); - } -} diff --git a/test/Contracts.test.js b/test/Contracts.test.js deleted file mode 100644 index df42ca5..0000000 --- a/test/Contracts.test.js +++ /dev/null @@ -1,138 +0,0 @@ -const { expect } = require("chai") -const { ethers } = require("hardhat") -const { hashRequest, hashBid, sign } = require("./marketplace") -const { exampleRequest, exampleBid } = require("./examples") - -describe("Contracts", function () { - const request = exampleRequest() - const bid = exampleBid() - - let client, host - let contracts - let requestHash, bidHash - let id - - beforeEach(async function () { - ;[client, host] = await ethers.getSigners() - let Contracts = await ethers.getContractFactory("TestContracts") - contracts = await Contracts.deploy() - requestHash = hashRequest(request) - bidHash = hashBid({ ...bid, requestHash }) - id = bidHash - }) - - it("creates a new storage contract", async function () { - await contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - await sign(host, bidHash) - ) - expect(await contracts.duration(id)).to.equal(request.duration) - expect(await contracts.size(id)).to.equal(request.size) - expect(await contracts.contentHash(id)).to.equal(request.contentHash) - expect(await contracts.price(id)).to.equal(bid.price) - expect(await contracts.host(id)).to.equal(await host.getAddress()) - }) - - it("does not allow reuse of contract ids", async function () { - await contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - await sign(host, bidHash) - ) - await expect( - contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - await sign(host, bidHash) - ) - ).to.be.revertedWith("Contract already exists") - }) - - it("cannot be created when client signature is invalid", async function () { - let invalidHash = hashRequest({ - ...request, - duration: request.duration + 1, - }) - let invalidSignature = await sign(client, invalidHash) - await expect( - contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - invalidSignature, - await sign(host, bidHash) - ) - ).to.be.revertedWith("Invalid signature") - }) - - it("cannot be created when host signature is invalid", async function () { - let invalidBid = hashBid({ ...bid, requestHash, price: bid.price - 1 }) - let invalidSignature = await sign(host, invalidBid) - await expect( - contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - invalidSignature - ) - ).to.be.revertedWith("Invalid signature") - }) - - it("cannot be created when bid has expired", async function () { - let expired = Math.round(Date.now() / 1000) - 60 // 1 minute ago - let bidHash = hashBid({ ...bid, requestHash, bidExpiry: expired }) - await expect( - contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - expired, - await sign(client, requestHash), - await sign(host, bidHash) - ) - ).to.be.revertedWith("Bid expired") - }) -}) diff --git a/test/Marketplace.test.js b/test/Marketplace.test.js index 1ed2526..a29c3ce 100644 --- a/test/Marketplace.test.js +++ b/test/Marketplace.test.js @@ -2,7 +2,7 @@ const { ethers } = require("hardhat") const { expect } = require("chai") const { exampleRequest, exampleOffer } = require("./examples") const { now, hours } = require("./time") -const { keccak256, defaultAbiCoder } = ethers.utils +const { requestId, offerId, requestToArray, offerToArray } = require("./ids") describe("Marketplace", function () { const collateral = 100 @@ -224,49 +224,3 @@ describe("Marketplace", function () { }) }) }) - -function requestId(request) { - return keccak256( - defaultAbiCoder.encode( - [ - "address", - "uint256", - "uint256", - "bytes32", - "uint256", - "uint256", - "uint256", - "uint256", - "bytes32", - ], - requestToArray(request) - ) - ) -} - -function offerId(offer) { - return keccak256( - defaultAbiCoder.encode( - ["address", "bytes32", "uint256", "uint256"], - offerToArray(offer) - ) - ) -} - -function requestToArray(request) { - return [ - request.client, - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.maxPrice, - request.expiry, - request.nonce, - ] -} - -function offerToArray(offer) { - return [offer.host, offer.requestId, offer.price, offer.expiry] -} diff --git a/test/Storage.test.js b/test/Storage.test.js index bd04789..0995185 100644 --- a/test/Storage.test.js +++ b/test/Storage.test.js @@ -1,198 +1,136 @@ const { expect } = require("chai") const { ethers, deployments } = require("hardhat") -const { hashRequest, hashBid, sign } = require("./marketplace") -const { exampleRequest, exampleBid } = require("./examples") +const { exampleRequest, exampleOffer } = require("./examples") const { mineBlock, minedBlockNumber } = require("./mining") +const { requestId, offerId } = require("./ids") describe("Storage", function () { - const request = exampleRequest() - const bid = exampleBid() - let storage let token let client, host + let request, offer let collateralAmount, slashMisses, slashPercentage + let id + + function switchAccount(account) { + token = token.connect(account) + storage = storage.connect(account) + } beforeEach(async function () { ;[client, host] = await ethers.getSigners() + await deployments.fixture(["TestToken", "Storage"]) token = await ethers.getContract("TestToken") storage = await ethers.getContract("Storage") + await token.mint(client.address, 1000) await token.mint(host.address, 1000) + collateralAmount = await storage.collateralAmount() slashMisses = await storage.slashMisses() slashPercentage = await storage.slashPercentage() + + request = exampleRequest() + request.client = client.address + + offer = exampleOffer() + offer.host = host.address + offer.requestId = requestId(request) + + switchAccount(client) + await token.approve(storage.address, request.maxPrice) + await storage.requestStorage(request) + switchAccount(host) + await token.approve(storage.address, collateralAmount) + await storage.deposit(collateralAmount) + await storage.offerStorage(offer) + switchAccount(client) + await storage.selectOffer(offerId(offer)) + id = offerId(offer) }) - describe("creating a new storage contract", function () { - let id + describe("starting the contract", function () { + it("starts requiring storage proofs", async function () { + switchAccount(host) + await storage.startContract(id) + expect(await storage.proofEnd(id)).to.be.gt(0) + }) + it("can only be done by the host", async function () { + switchAccount(client) + await expect(storage.startContract(id)).to.be.revertedWith( + "Only host can call this function" + ) + }) + + it("can only be done once", async function () { + switchAccount(host) + await storage.startContract(id) + await expect(storage.startContract(id)).to.be.reverted + }) + }) + + describe("finishing the contract", function () { beforeEach(async function () { - await token.connect(host).approve(storage.address, collateralAmount) - await token.connect(client).approve(storage.address, bid.price) - await storage.connect(host).deposit(collateralAmount) - let requestHash = hashRequest(request) - let bidHash = hashBid({ ...bid, requestHash }) - await storage.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - await sign(host, bidHash) - ) - id = bidHash + switchAccount(host) + await storage.startContract(id) }) - it("created the contract", async function () { - expect(await storage.duration(id)).to.equal(request.duration) - expect(await storage.size(id)).to.equal(request.size) - expect(await storage.contentHash(id)).to.equal(request.contentHash) - expect(await storage.proofPeriod(id)).to.equal(request.proofPeriod) - expect(await storage.proofTimeout(id)).to.equal(request.proofTimeout) - expect(await storage.price(id)).to.equal(bid.price) - expect(await storage.host(id)).to.equal(await host.getAddress()) + async function mineUntilEnd() { + const end = await storage.proofEnd(id) + while ((await minedBlockNumber()) < end) { + await mineBlock() + } + } + + it("pays the host", async function () { + await mineUntilEnd() + const startBalance = await token.balanceOf(host.address) + await storage.finishContract(id) + const endBalance = await token.balanceOf(host.address) + expect(endBalance - startBalance).to.equal(offer.price) }) - it("locks up host collateral", async function () { - await expect(storage.connect(host).withdraw()).to.be.revertedWith( - "Account locked" + it("is only allowed when end time has passed", async function () { + await expect(storage.finishContract(id)).to.be.revertedWith( + "Contract has not ended yet" ) }) - describe("starting the contract", function () { - it("starts requiring storage proofs", async function () { - await storage.connect(host).startContract(id) - expect(await storage.proofEnd(id)).to.be.gt(0) - }) - - it("can only be done by the host", async function () { - await expect( - storage.connect(client).startContract(id) - ).to.be.revertedWith("Only host can call this function") - }) - - it("can only be done once", async function () { - await storage.connect(host).startContract(id) - await expect(storage.connect(host).startContract(id)).to.be.reverted - }) - }) - - describe("finishing the contract", function () { - beforeEach(async function () { - await storage.connect(host).startContract(id) - }) - - async function mineUntilEnd() { - const end = await storage.proofEnd(id) - while ((await minedBlockNumber()) < end) { - await mineBlock() - } - } - - it("unlocks the host collateral", async function () { - await mineUntilEnd() - await storage.finishContract(id) - await expect(storage.connect(host).withdraw()).not.to.be.reverted - }) - - it("pays the host", async function () { - await mineUntilEnd() - const startBalance = await token.balanceOf(host.address) - await storage.finishContract(id) - const endBalance = await token.balanceOf(host.address) - expect(endBalance - startBalance).to.equal(bid.price) - }) - - it("is only allowed when end time has passed", async function () { - await expect(storage.finishContract(id)).to.be.revertedWith( - "Contract has not ended yet" - ) - }) - - it("can only be done once", async function () { - await mineUntilEnd() - await storage.finishContract(id) - await expect(storage.finishContract(id)).to.be.revertedWith( - "Contract already finished" - ) - }) - }) - - describe("slashing when missing proofs", function () { - async function ensureProofIsMissing() { - while (!(await storage.isProofRequired(id, await minedBlockNumber()))) { - mineBlock() - } - const blocknumber = await minedBlockNumber() - for (let i = 0; i < request.proofTimeout; i++) { - mineBlock() - } - await storage.markProofAsMissing(id, blocknumber) - } - - it("reduces collateral when too many proofs are missing", async function () { - await storage.connect(host).startContract(id) - for (let i = 0; i < slashMisses; i++) { - await ensureProofIsMissing() - } - const expectedBalance = - (collateralAmount * (100 - slashPercentage)) / 100 - expect(await storage.balanceOf(host.address)).to.equal(expectedBalance) - }) + it("can only be done once", async function () { + await mineUntilEnd() + await storage.finishContract(id) + await expect(storage.finishContract(id)).to.be.revertedWith( + "Contract already finished" + ) }) }) - it("doesn't create contract with insufficient collateral", async function () { - await token.connect(host).approve(storage.address, collateralAmount - 1) - await token.connect(client).approve(storage.address, bid.price) - await storage.connect(host).deposit(collateralAmount - 1) - let requestHash = hashRequest(request) - let bidHash = hashBid({ ...bid, requestHash }) - await expect( - storage.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - await sign(host, bidHash) - ) - ).to.be.revertedWith("Insufficient collateral") - }) + describe("slashing when missing proofs", function () { + beforeEach(function () { + switchAccount(host) + }) - it("doesn't create contract without payment of price", async function () { - await token.connect(host).approve(storage.address, collateralAmount) - await token.connect(client).approve(storage.address, bid.price - 1) - await storage.connect(host).deposit(collateralAmount) - let requestHash = hashRequest(request) - let bidHash = hashBid({ ...bid, requestHash }) - await expect( - storage.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - await sign(host, bidHash) - ) - ).to.be.revertedWith("ERC20: transfer amount exceeds allowance") + async function ensureProofIsMissing() { + while (!(await storage.isProofRequired(id, await minedBlockNumber()))) { + mineBlock() + } + const blocknumber = await minedBlockNumber() + for (let i = 0; i < request.proofTimeout; i++) { + mineBlock() + } + await storage.markProofAsMissing(id, blocknumber) + } + + it("reduces collateral when too many proofs are missing", async function () { + await storage.connect(host).startContract(id) + for (let i = 0; i < slashMisses; i++) { + await ensureProofIsMissing() + } + const expectedBalance = (collateralAmount * (100 - slashPercentage)) / 100 + expect(await storage.balanceOf(host.address)).to.equal(expectedBalance) + }) }) }) diff --git a/test/ids.js b/test/ids.js new file mode 100644 index 0000000..e7be9c8 --- /dev/null +++ b/test/ids.js @@ -0,0 +1,50 @@ +const { ethers } = require("hardhat") +const { keccak256, defaultAbiCoder } = ethers.utils + +function requestId(request) { + return keccak256( + defaultAbiCoder.encode( + [ + "address", + "uint256", + "uint256", + "bytes32", + "uint256", + "uint256", + "uint256", + "uint256", + "bytes32", + ], + requestToArray(request) + ) + ) +} + +function offerId(offer) { + return keccak256( + defaultAbiCoder.encode( + ["address", "bytes32", "uint256", "uint256"], + offerToArray(offer) + ) + ) +} + +function requestToArray(request) { + return [ + request.client, + request.duration, + request.size, + request.contentHash, + request.proofPeriod, + request.proofTimeout, + request.maxPrice, + request.expiry, + request.nonce, + ] +} + +function offerToArray(offer) { + return [offer.host, offer.requestId, offer.price, offer.expiry] +} + +module.exports = { requestId, offerId, requestToArray, offerToArray } diff --git a/test/marketplace.js b/test/marketplace.js deleted file mode 100644 index 7b9e930..0000000 --- a/test/marketplace.js +++ /dev/null @@ -1,34 +0,0 @@ -const { ethers } = require("hardhat") - -function hashRequest({ - duration, - size, - contentHash, - proofPeriod, - proofTimeout, - nonce, -}) { - const type = "[dagger.request.v1]" - return ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( - ["string", "uint", "uint", "bytes32", "uint", "uint", "bytes32"], - [type, duration, size, contentHash, proofPeriod, proofTimeout, nonce] - ) - ) -} - -function hashBid({ requestHash, bidExpiry, price }) { - const type = "[dagger.bid.v1]" - return ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( - ["string", "bytes32", "uint", "uint"], - [type, requestHash, bidExpiry, price] - ) - ) -} - -async function sign(signer, hash) { - return await signer.signMessage(ethers.utils.arrayify(hash)) -} - -module.exports = { hashRequest, hashBid, sign }