mirror of
https://github.com/logos-storage/logos-storage-contracts-eth.git
synced 2026-01-03 22:03:08 +00:00
Move to ethers 6 and use hardhat ignition for deployments
This commit is contained in:
parent
2dddc26015
commit
de58989edf
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -10,7 +10,6 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
jobs:
|
||||
formatting:
|
||||
runs-on: ubuntu-latest
|
||||
@ -29,7 +28,7 @@ jobs:
|
||||
# workaround for https://github.com/NomicFoundation/hardhat/issues/3877
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.15
|
||||
node-version: 22
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
- uses: actions/cache@v4
|
||||
@ -53,9 +52,9 @@ jobs:
|
||||
- name: Install Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '11'
|
||||
java-package: 'jre'
|
||||
distribution: "zulu"
|
||||
java-version: "11"
|
||||
java-package: "jre"
|
||||
|
||||
- name: Install Certora CLI
|
||||
run: pip3 install certora-cli==7.10.2
|
||||
@ -88,4 +87,3 @@ jobs:
|
||||
rule:
|
||||
- verify:marketplace
|
||||
- verify:state_changes
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@ artifacts
|
||||
deployment-localhost.json
|
||||
crytic-export
|
||||
.certora_internal
|
||||
coverage
|
||||
coverage.json
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
require("@nomiclabs/hardhat-waffle")
|
||||
require("hardhat-deploy")
|
||||
require("hardhat-deploy-ethers")
|
||||
require("@nomicfoundation/hardhat-toolbox")
|
||||
|
||||
module.exports = {
|
||||
solidity: {
|
||||
|
||||
15
ignition/modules/endian.js
Normal file
15
ignition/modules/endian.js
Normal file
@ -0,0 +1,15 @@
|
||||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
|
||||
|
||||
module.exports = buildModule("Endian", (m) => {
|
||||
const deployer = m.getAccount(0)
|
||||
|
||||
const endian = m.contract("Endian", [], {
|
||||
from: deployer,
|
||||
})
|
||||
|
||||
const testEndian = m.contract("TestEndian", [], {
|
||||
from: deployer,
|
||||
})
|
||||
|
||||
return { endian, testEndian }
|
||||
})
|
||||
56
ignition/modules/marketplace.js
Normal file
56
ignition/modules/marketplace.js
Normal file
@ -0,0 +1,56 @@
|
||||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
|
||||
const { loadZkeyHash } = require("../../verifier/verifier.js")
|
||||
const { loadConfiguration } = require("../../configuration/configuration.js")
|
||||
const TokenModule = require("./token.js")
|
||||
const VerifierModule = require("./verifier.js")
|
||||
|
||||
function getDefaultConfig() {
|
||||
const zkeyHash = loadZkeyHash(hre.network.name)
|
||||
const config = loadConfiguration(hre.network.name)
|
||||
config.proofs.zkeyHash = zkeyHash
|
||||
return config
|
||||
}
|
||||
|
||||
function getDefaultVerifier(m) {
|
||||
const { verifier } = m.useModule(VerifierModule)
|
||||
return verifier
|
||||
}
|
||||
|
||||
module.exports = buildModule("Marketplace", (m) => {
|
||||
const deployer = m.getAccount(0)
|
||||
|
||||
const { token } = m.useModule(TokenModule)
|
||||
const { verifier } = m.useModule(VerifierModule)
|
||||
const configuration = m.getParameter("configuration", getDefaultConfig())
|
||||
|
||||
const marketplace = m.contract(
|
||||
"Marketplace",
|
||||
[configuration, token, verifier],
|
||||
{
|
||||
from: deployer,
|
||||
}
|
||||
)
|
||||
|
||||
let testMarketplace
|
||||
|
||||
if (hre.network.config.tags.includes("local")) {
|
||||
const { testVerifier } = m.useModule(VerifierModule)
|
||||
|
||||
testMarketplace = m.contract(
|
||||
"TestMarketplace",
|
||||
[configuration, token, testVerifier],
|
||||
{
|
||||
from: deployer,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
marketplace,
|
||||
testMarketplace,
|
||||
token,
|
||||
}
|
||||
})
|
||||
|
||||
// // Tags and dependencies
|
||||
// module.exports.tags = ["Marketplace"]
|
||||
12
ignition/modules/periods.js
Normal file
12
ignition/modules/periods.js
Normal file
@ -0,0 +1,12 @@
|
||||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
|
||||
|
||||
module.exports = buildModule("Periods", (m) => {
|
||||
const deployer = m.getAccount(0)
|
||||
const secondsPerPeriod = m.getParameter("secondsPerPeriod", 0)
|
||||
|
||||
const periods = m.contract("Periods", [secondsPerPeriod], {
|
||||
from: deployer,
|
||||
})
|
||||
|
||||
return { periods }
|
||||
})
|
||||
15
ignition/modules/proofs.js
Normal file
15
ignition/modules/proofs.js
Normal file
@ -0,0 +1,15 @@
|
||||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
|
||||
const VerifierModule = require("./verifier.js")
|
||||
|
||||
module.exports = buildModule("Proofs", (m) => {
|
||||
const deployer = m.getAccount(0)
|
||||
|
||||
const { verifier } = m.useModule(VerifierModule)
|
||||
const configuration = m.getParameter("configuration", null)
|
||||
|
||||
const testProofs = m.contract("TestProofs", [configuration, verifier], {
|
||||
from: deployer,
|
||||
})
|
||||
|
||||
return { testProofs }
|
||||
})
|
||||
17
ignition/modules/slot-reservations.js
Normal file
17
ignition/modules/slot-reservations.js
Normal file
@ -0,0 +1,17 @@
|
||||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
|
||||
|
||||
module.exports = buildModule("SlotReservations", (m) => {
|
||||
const deployer = m.getAccount(0)
|
||||
|
||||
const configuration = m.getParameter("configuration", null)
|
||||
|
||||
const testSlotReservations = m.contract(
|
||||
"TestSlotReservations",
|
||||
[configuration],
|
||||
{
|
||||
from: deployer,
|
||||
}
|
||||
)
|
||||
|
||||
return { testSlotReservations }
|
||||
})
|
||||
22
ignition/modules/token.js
Normal file
22
ignition/modules/token.js
Normal file
@ -0,0 +1,22 @@
|
||||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
|
||||
|
||||
const MAX_ACCOUNTS = 20
|
||||
const MINTED_TOKENS = 1_000_000_000_000_000n
|
||||
|
||||
module.exports = buildModule("Token", (m) => {
|
||||
const deployer = m.getAccount(0)
|
||||
|
||||
const token = m.contract("TestToken", [], {
|
||||
from: deployer,
|
||||
})
|
||||
|
||||
if (hre.network.config.tags.includes("local")) {
|
||||
for (let i = 0; i < MAX_ACCOUNTS; i++) {
|
||||
const account = m.getAccount(i)
|
||||
const futureId = "SendingEth" + i
|
||||
m.send(futureId, account, MINTED_TOKENS)
|
||||
}
|
||||
}
|
||||
|
||||
return { token }
|
||||
})
|
||||
17
ignition/modules/verifier.js
Normal file
17
ignition/modules/verifier.js
Normal file
@ -0,0 +1,17 @@
|
||||
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
|
||||
const { loadVerificationKey } = require("../../verifier/verifier.js")
|
||||
|
||||
module.exports = buildModule("Verifier", (m) => {
|
||||
const deployer = m.getAccount(0)
|
||||
|
||||
const verificationKey = loadVerificationKey(hre.network.name)
|
||||
const verifier = m.contract("Groth16Verifier", [verificationKey], {
|
||||
from: deployer,
|
||||
})
|
||||
|
||||
const testVerifier = m.contract("TestVerifier", [], {
|
||||
from: deployer,
|
||||
})
|
||||
|
||||
return { verifier, testVerifier }
|
||||
})
|
||||
35068
package-lock.json
generated
35068
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@ -2,29 +2,28 @@
|
||||
"name": "codex-contracts-eth",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "npm run lint && hardhat test",
|
||||
"test": "npm run lint && hardhat test --parallel",
|
||||
"fuzz": "hardhat compile && fuzzing/fuzz.sh",
|
||||
"start": "hardhat node --export deployment-localhost.json",
|
||||
"start": "hardhat node",
|
||||
"compile": "hardhat compile",
|
||||
"format": "prettier --write contracts/*.sol contracts/**/*.sol test/**/*.js",
|
||||
"format:check": "prettier --check contracts/*.sol contracts/**/*.sol test/**/*.js",
|
||||
"lint": "solhint contracts/**.sol",
|
||||
"deploy": "hardhat deploy",
|
||||
"deploy": "npx hardhat run scripts/deploy.js",
|
||||
"verify": "npm run verify:marketplace && npm run verify:state_changes",
|
||||
"verify:marketplace": "certoraRun certora/confs/Marketplace.conf",
|
||||
"verify:state_changes": "certoraRun certora/confs/StateChanges.conf"
|
||||
"verify:state_changes": "certoraRun certora/confs/StateChanges.conf",
|
||||
"coverage": "npx hardhat coverage",
|
||||
"gas:report": "REPORT_GAS=true npx hardhat test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.2.1",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.3",
|
||||
"@openzeppelin/contracts": "^5.3.0",
|
||||
"@stdlib/stats-binomial-test": "^0.0.7",
|
||||
"@nomicfoundation/hardhat-chai-matchers": "^2.0.8",
|
||||
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
||||
"@stdlib/stats-binomial-test": "^0.2.2",
|
||||
"chai": "^4.3.7",
|
||||
"ethereum-waffle": "^3.4.4",
|
||||
"ethers": "^5.7.2",
|
||||
"ethers": "6.14.3",
|
||||
"hardhat": "^2.24.2",
|
||||
"hardhat-deploy": "^0.11.34",
|
||||
"hardhat-deploy-ethers": "^0.3.0-beta.13",
|
||||
"prettier": "^2.8.2",
|
||||
"prettier-plugin-solidity": "^1.4.2",
|
||||
"solhint": "^5.0.5"
|
||||
|
||||
24
scripts/deploy.js
Normal file
24
scripts/deploy.js
Normal file
@ -0,0 +1,24 @@
|
||||
const hre = require("hardhat")
|
||||
const { mine } = require("@nomicfoundation/hardhat-network-helpers")
|
||||
|
||||
const MarketplaceModule = require("../ignition/modules/marketplace")
|
||||
|
||||
async function main() {
|
||||
if (hre.network.config.tags.includes("local")) {
|
||||
await mine(256)
|
||||
}
|
||||
|
||||
const { marketplace, testMarketplace } = await hre.ignition.deploy(
|
||||
MarketplaceModule
|
||||
)
|
||||
|
||||
console.info("Deployed Marketplace with Groth16 Verifier at:")
|
||||
console.log(await marketplace.getAddress())
|
||||
|
||||
console.log()
|
||||
|
||||
console.info("Deployed Marketplace with Test Verifier at:")
|
||||
console.log(await testMarketplace.getAddress())
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
@ -1,5 +1,5 @@
|
||||
const { expect } = require("chai")
|
||||
const { ethers } = require("hardhat")
|
||||
const EndianModule = require("../ignition/modules/endian")
|
||||
|
||||
describe("Endian", function () {
|
||||
const big =
|
||||
@ -10,8 +10,8 @@ describe("Endian", function () {
|
||||
let endian
|
||||
|
||||
beforeEach(async function () {
|
||||
let Endian = await ethers.getContractFactory("TestEndian")
|
||||
endian = await Endian.deploy()
|
||||
const { testEndian } = await ignition.deploy(EndianModule)
|
||||
endian = testEndian
|
||||
})
|
||||
|
||||
it("converts from little endian to big endian", async function () {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,35 @@
|
||||
const { expect } = require("chai")
|
||||
const { ethers } = require("hardhat")
|
||||
const PeriodsModule = require("../ignition/modules/periods")
|
||||
|
||||
describe("Periods", function () {
|
||||
it("should revert when secondsPerPeriod is 0", async function () {
|
||||
const PeriodsContract = await ethers.getContractFactory("Periods")
|
||||
await expect(PeriodsContract.deploy(0)).to.be.revertedWith(
|
||||
"Periods_InvalidSecondsPerPeriod"
|
||||
)
|
||||
const promise = ignition.deploy(PeriodsModule, {
|
||||
parameters: {
|
||||
Periods: {
|
||||
secondsPerPeriod: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
const expectedError = "Periods_InvalidSecondsPerPeriod"
|
||||
|
||||
const error = await expect(promise).to.be.rejected
|
||||
expect(error)
|
||||
.to.have.property("message")
|
||||
.that.contains(
|
||||
expectedError,
|
||||
`Expected error ${expectedError}, but got ${error.message}`
|
||||
)
|
||||
})
|
||||
|
||||
it("should not revert when secondsPerPeriod more than 0", async function () {
|
||||
const PeriodsContract = await ethers.getContractFactory("Periods")
|
||||
await expect(PeriodsContract.deploy(10)).not.to.be.reverted
|
||||
const promise = ignition.deploy(PeriodsModule, {
|
||||
parameters: {
|
||||
Periods: {
|
||||
secondsPerPeriod: 10,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await expect(promise).not.to.be.rejected
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,20 +1,21 @@
|
||||
const { expect } = require("chai")
|
||||
const { ethers, deployments } = require("hardhat")
|
||||
const { hexlify, randomBytes } = ethers.utils
|
||||
const { ethers } = require("hardhat")
|
||||
const { hexlify, randomBytes } = ethers
|
||||
const {
|
||||
snapshot,
|
||||
revert,
|
||||
mine,
|
||||
ensureMinimumBlockHeight,
|
||||
currentTime,
|
||||
advanceTime,
|
||||
advanceTimeTo,
|
||||
mine,
|
||||
} = require("./evm")
|
||||
const { periodic } = require("./time")
|
||||
const { loadProof, loadPublicInput } = require("../verifier/verifier")
|
||||
const { SlotState } = require("./requests")
|
||||
const binomialTest = require("@stdlib/stats-binomial-test")
|
||||
const { exampleProof } = require("./examples")
|
||||
const ProofsModule = require("../ignition/modules/proofs")
|
||||
|
||||
describe("Proofs", function () {
|
||||
const slotId = hexlify(randomBytes(32))
|
||||
@ -30,13 +31,22 @@ describe("Proofs", function () {
|
||||
beforeEach(async function () {
|
||||
await snapshot()
|
||||
await ensureMinimumBlockHeight(256)
|
||||
const Proofs = await ethers.getContractFactory("TestProofs")
|
||||
await deployments.fixture(["Verifier"])
|
||||
const verifier = await deployments.get("Groth16Verifier")
|
||||
proofs = await Proofs.deploy(
|
||||
{ period, timeout, downtime, zkeyHash: "", downtimeProduct },
|
||||
verifier.address
|
||||
)
|
||||
|
||||
const { testProofs } = await ignition.deploy(ProofsModule, {
|
||||
parameters: {
|
||||
Proofs: {
|
||||
configuration: {
|
||||
period,
|
||||
timeout,
|
||||
downtime,
|
||||
zkeyHash: "",
|
||||
downtimeProduct,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
proofs = testProofs
|
||||
})
|
||||
|
||||
afterEach(async function () {
|
||||
@ -113,7 +123,7 @@ describe("Proofs", function () {
|
||||
let previous = await proofs.getPointer(slotId)
|
||||
await mine()
|
||||
let current = await proofs.getPointer(slotId)
|
||||
expect(current).to.equal((previous + 1) % 256)
|
||||
expect(current).to.equal((previous + 1n) % 256n)
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -203,14 +213,14 @@ describe("Proofs", function () {
|
||||
let invalid = exampleProof()
|
||||
await expect(
|
||||
proofs.proofReceived(slotId, invalid, pubSignals)
|
||||
).to.be.revertedWith("Proofs_InvalidProof")
|
||||
).to.be.revertedWithCustomError(proofs, "Proofs_InvalidProof")
|
||||
})
|
||||
|
||||
it("fails proof submission when public input is incorrect", async function () {
|
||||
let invalid = [1, 2, 3]
|
||||
await expect(
|
||||
proofs.proofReceived(slotId, proof, invalid)
|
||||
).to.be.revertedWith("Proofs_InvalidProof")
|
||||
).to.be.revertedWithCustomError(proofs, "Proofs_InvalidProof")
|
||||
})
|
||||
|
||||
it("emits an event when proof was submitted", async function () {
|
||||
@ -223,7 +233,7 @@ describe("Proofs", function () {
|
||||
await proofs.proofReceived(slotId, proof, pubSignals)
|
||||
await expect(
|
||||
proofs.proofReceived(slotId, proof, pubSignals)
|
||||
).to.be.revertedWith("Proofs_ProofAlreadySubmitted")
|
||||
).to.be.revertedWithCustomError(proofs, "Proofs_ProofAlreadySubmitted")
|
||||
})
|
||||
|
||||
it("marks a proof as missing", async function () {
|
||||
@ -240,7 +250,7 @@ describe("Proofs", function () {
|
||||
let currentPeriod = periodOf(await currentTime())
|
||||
await expect(
|
||||
proofs.markProofAsMissing(slotId, currentPeriod)
|
||||
).to.be.revertedWith("Proofs_PeriodNotEnded")
|
||||
).to.be.revertedWithCustomError(proofs, "Proofs_PeriodNotEnded")
|
||||
})
|
||||
|
||||
it("does not mark a proof as missing after timeout", async function () {
|
||||
@ -249,7 +259,7 @@ describe("Proofs", function () {
|
||||
await advanceTimeTo(periodEnd(currentPeriod) + timeout + 1)
|
||||
await expect(
|
||||
proofs.markProofAsMissing(slotId, currentPeriod)
|
||||
).to.be.revertedWith("Proofs_ValidationTimedOut")
|
||||
).to.be.revertedWithCustomError(proofs, "Proofs_ValidationTimedOut")
|
||||
})
|
||||
|
||||
it("does not mark a received proof as missing", async function () {
|
||||
@ -259,7 +269,7 @@ describe("Proofs", function () {
|
||||
await advanceTimeTo(periodEnd(receivedPeriod) + 1)
|
||||
await expect(
|
||||
proofs.markProofAsMissing(slotId, receivedPeriod)
|
||||
).to.be.revertedWith("Proofs_ProofNotMissing")
|
||||
).to.be.revertedWithCustomError(proofs, "Proofs_ProofNotMissing")
|
||||
})
|
||||
|
||||
it("does not mark proof as missing when not required", async function () {
|
||||
@ -270,7 +280,7 @@ describe("Proofs", function () {
|
||||
await advanceTimeTo(periodEnd(currentPeriod) + 1)
|
||||
await expect(
|
||||
proofs.markProofAsMissing(slotId, currentPeriod)
|
||||
).to.be.revertedWith("Proofs_ProofNotRequired")
|
||||
).to.be.revertedWithCustomError(proofs, "Proofs_ProofNotRequired")
|
||||
})
|
||||
|
||||
it("does not mark proof as missing twice", async function () {
|
||||
@ -280,7 +290,10 @@ describe("Proofs", function () {
|
||||
await proofs.markProofAsMissing(slotId, missedPeriod)
|
||||
await expect(
|
||||
proofs.markProofAsMissing(slotId, missedPeriod)
|
||||
).to.be.revertedWith("Proofs_ProofAlreadyMarkedMissing")
|
||||
).to.be.revertedWithCustomError(
|
||||
proofs,
|
||||
"Proofs_ProofAlreadyMarkedMissing"
|
||||
)
|
||||
})
|
||||
|
||||
it("requires no proofs when slot is finished", async function () {
|
||||
|
||||
@ -3,6 +3,7 @@ const { ethers } = require("hardhat")
|
||||
const { exampleRequest, exampleConfiguration } = require("./examples")
|
||||
const { requestId, slotId } = require("./ids")
|
||||
const { SlotState } = require("./requests")
|
||||
const SlotReservationsModule = require("../ignition/modules/slot-reservations")
|
||||
|
||||
describe("SlotReservations", function () {
|
||||
let reservations
|
||||
@ -15,10 +16,18 @@ describe("SlotReservations", function () {
|
||||
const config = exampleConfiguration()
|
||||
|
||||
beforeEach(async function () {
|
||||
let SlotReservations = await ethers.getContractFactory(
|
||||
"TestSlotReservations"
|
||||
const { testSlotReservations } = await ignition.deploy(
|
||||
SlotReservationsModule,
|
||||
{
|
||||
parameters: {
|
||||
SlotReservations: {
|
||||
configuration: config.reservations,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
reservations = await SlotReservations.deploy(config.reservations)
|
||||
|
||||
reservations = testSlotReservations
|
||||
;[provider, address1, address2, address3] = await ethers.getSigners()
|
||||
|
||||
request = await exampleRequest()
|
||||
@ -76,7 +85,10 @@ describe("SlotReservations", function () {
|
||||
|
||||
it("cannot reserve a slot more than once", async function () {
|
||||
await reservations.reserveSlot(reqId, slotIndex)
|
||||
await expect(reservations.reserveSlot(reqId, slotIndex)).to.be.revertedWith(
|
||||
await expect(
|
||||
reservations.reserveSlot(reqId, slotIndex)
|
||||
).to.be.revertedWithCustomError(
|
||||
reservations,
|
||||
"SlotReservations_ReservationNotAllowed"
|
||||
)
|
||||
expect(await reservations.length(id)).to.equal(1)
|
||||
@ -95,7 +107,10 @@ describe("SlotReservations", function () {
|
||||
switchAccount(address3)
|
||||
await reservations.reserveSlot(reqId, slotIndex)
|
||||
switchAccount(provider)
|
||||
await expect(reservations.reserveSlot(reqId, slotIndex)).to.be.revertedWith(
|
||||
await expect(
|
||||
reservations.reserveSlot(reqId, slotIndex)
|
||||
).to.be.revertedWithCustomError(
|
||||
reservations,
|
||||
"SlotReservations_ReservationNotAllowed"
|
||||
)
|
||||
expect(await reservations.length(id)).to.equal(3)
|
||||
@ -115,7 +130,10 @@ describe("SlotReservations", function () {
|
||||
|
||||
it("cannot reserve a slot if not free or not in repair", async function () {
|
||||
await reservations.setSlotState(id, SlotState.Filled)
|
||||
await expect(reservations.reserveSlot(reqId, slotIndex)).to.be.revertedWith(
|
||||
await expect(
|
||||
reservations.reserveSlot(reqId, slotIndex)
|
||||
).to.be.revertedWithCustomError(
|
||||
reservations,
|
||||
"SlotReservations_ReservationNotAllowed"
|
||||
)
|
||||
expect(await reservations.length(id)).to.equal(0)
|
||||
|
||||
59
test/evm.js
59
test/evm.js
@ -1,63 +1,52 @@
|
||||
const { ethers } = require("hardhat")
|
||||
const {
|
||||
time,
|
||||
mine,
|
||||
takeSnapshot,
|
||||
setNextBlockTimestamp,
|
||||
} = require("@nomicfoundation/hardhat-network-helpers")
|
||||
|
||||
let snapshots = []
|
||||
const snapshots = []
|
||||
|
||||
async function snapshot() {
|
||||
const id = await ethers.provider.send("evm_snapshot")
|
||||
const time = await currentTime()
|
||||
const snapshot = await takeSnapshot()
|
||||
const automine = await ethers.provider.send("hardhat_getAutomine")
|
||||
snapshots.push({ id, time, automine })
|
||||
const time = await currentTime()
|
||||
snapshots.push({ snapshot, automine, time })
|
||||
}
|
||||
|
||||
async function revert() {
|
||||
const { id, time, automine } = snapshots.pop()
|
||||
await ethers.provider.send("evm_revert", [id])
|
||||
|
||||
const current = await currentTime()
|
||||
const nextTime = Math.max(time + 1, current + 1)
|
||||
|
||||
await ethers.provider.send("evm_setNextBlockTimestamp", [nextTime])
|
||||
await ethers.provider.send("evm_setAutomine", [automine])
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables Hardhat's automine mode.
|
||||
*
|
||||
* When automine mode is disabled, transactions that revert are silently ignored!
|
||||
*/
|
||||
async function setAutomine(enabled) {
|
||||
await ethers.provider.send("evm_setAutomine", [enabled])
|
||||
}
|
||||
|
||||
async function mine() {
|
||||
await ethers.provider.send("evm_mine")
|
||||
const { snapshot, time, automine } = snapshots.pop()
|
||||
if (snapshot) {
|
||||
setNextBlockTimestamp(time)
|
||||
await ethers.provider.send("evm_setAutomine", [automine])
|
||||
return snapshot.restore()
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureMinimumBlockHeight(height) {
|
||||
while ((await ethers.provider.getBlockNumber()) < height) {
|
||||
while ((await time.latestBlock()) < height) {
|
||||
await mine()
|
||||
}
|
||||
}
|
||||
|
||||
async function setNextBlockTimestamp(timestamp) {
|
||||
return time.setNextBlockTimestamp(timestamp)
|
||||
}
|
||||
|
||||
async function currentTime() {
|
||||
let block = await ethers.provider.getBlock("latest")
|
||||
return block.timestamp
|
||||
return time.latest()
|
||||
}
|
||||
|
||||
async function advanceTime(seconds) {
|
||||
await ethers.provider.send("evm_increaseTime", [seconds])
|
||||
await time.increase(seconds)
|
||||
await mine()
|
||||
}
|
||||
|
||||
async function advanceTimeTo(timestamp) {
|
||||
await setNextBlockTimestamp(timestamp)
|
||||
await time.setNextBlockTimestamp(timestamp)
|
||||
await mine()
|
||||
}
|
||||
|
||||
async function setNextBlockTimestamp(timestamp) {
|
||||
await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp])
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
snapshot,
|
||||
revert,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
const { ethers } = require("hardhat")
|
||||
const { hours } = require("./time")
|
||||
const { hexlify, randomBytes } = ethers.utils
|
||||
const { hexlify, randomBytes } = require("hardhat").ethers
|
||||
|
||||
const exampleConfiguration = () => ({
|
||||
collateral: {
|
||||
@ -36,7 +35,7 @@ const exampleRequest = async () => {
|
||||
},
|
||||
content: {
|
||||
cid: Buffer.from("zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob"),
|
||||
merkleRoot: Array.from(randomBytes(32)),
|
||||
merkleRoot: randomBytes(32),
|
||||
},
|
||||
expiry: hours(1),
|
||||
nonce: hexlify(randomBytes(32)),
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
const { ethers } = require("hardhat")
|
||||
const { keccak256, defaultAbiCoder } = ethers.utils
|
||||
const { keccak256, AbiCoder } = require("hardhat").ethers
|
||||
|
||||
function requestId(request) {
|
||||
const Ask = "tuple(uint256, uint256, uint256, uint64, uint64, uint64, int64)"
|
||||
const Content = "tuple(bytes, bytes32)"
|
||||
const Request =
|
||||
"tuple(address, " + Ask + ", " + Content + ", uint64, bytes32)"
|
||||
return keccak256(defaultAbiCoder.encode([Request], requestToArray(request)))
|
||||
return keccak256(new AbiCoder().encode([Request], requestToArray(request)))
|
||||
}
|
||||
|
||||
function askToArray(ask) {
|
||||
@ -40,7 +39,7 @@ function requestToArray(request) {
|
||||
function slotId(slot) {
|
||||
const types = "tuple(bytes32, uint256)"
|
||||
const values = [slot.request, slot.index]
|
||||
const encoding = defaultAbiCoder.encode([types], [values])
|
||||
const encoding = new AbiCoder().encode([types], [values])
|
||||
return keccak256(encoding)
|
||||
}
|
||||
|
||||
|
||||
@ -4,16 +4,16 @@ const { payoutForDuration } = require("./price")
|
||||
const { collateralPerSlot } = require("./collateral")
|
||||
|
||||
async function waitUntilCancelled(contract, request) {
|
||||
const expiry = (await contract.requestExpiry(requestId(request))).toNumber()
|
||||
const expiry = await contract.requestExpiry(requestId(request))
|
||||
// We do +1, because the expiry check in contract is done as `>` and not `>=`.
|
||||
await advanceTimeTo(expiry + 1)
|
||||
return advanceTimeTo(expiry + 1n)
|
||||
}
|
||||
|
||||
async function waitUntilSlotsFilled(contract, request, proof, token, slots) {
|
||||
let collateral = collateralPerSlot(request)
|
||||
await token.approve(contract.address, collateral * slots.length)
|
||||
await token.approve(await contract.getAddress(), collateral * slots.length)
|
||||
|
||||
let requestEnd = (await contract.requestEnd(requestId(request))).toNumber()
|
||||
let requestEnd = await contract.requestEnd(requestId(request))
|
||||
const payouts = []
|
||||
for (let slotIndex of slots) {
|
||||
await contract.reserveSlot(requestId(request), slotIndex)
|
||||
@ -40,9 +40,9 @@ async function waitUntilStarted(contract, request, proof, token) {
|
||||
}
|
||||
|
||||
async function waitUntilFinished(contract, requestId) {
|
||||
const end = (await contract.requestEnd(requestId)).toNumber()
|
||||
const end = await contract.requestEnd(requestId)
|
||||
// We do +1, because the end check in contract is done as `>` and not `>=`.
|
||||
await advanceTimeTo(end + 1)
|
||||
await advanceTimeTo(end + 1n)
|
||||
}
|
||||
|
||||
async function waitUntilFailed(contract, request) {
|
||||
@ -96,6 +96,11 @@ function patchOverloads(contract) {
|
||||
}
|
||||
}
|
||||
|
||||
function littleEndianToBigInt(littleEndian) {
|
||||
const buffer = Buffer.from(littleEndian)
|
||||
return BigInt(`0x${buffer.toString("hex")}`)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
waitUntilCancelled,
|
||||
waitUntilStarted,
|
||||
@ -104,4 +109,5 @@ module.exports = {
|
||||
waitUntilFailed,
|
||||
waitUntilSlotFailed,
|
||||
patchOverloads,
|
||||
littleEndianToBigInt,
|
||||
}
|
||||
|
||||
@ -9,7 +9,21 @@ function maxPrice(request) {
|
||||
}
|
||||
|
||||
function payoutForDuration(request, start, end) {
|
||||
return (end - start) * pricePerSlotPerSecond(request)
|
||||
return (Number(end) - Number(start)) * pricePerSlotPerSecond(request)
|
||||
}
|
||||
|
||||
module.exports = { maxPrice, pricePerSlotPerSecond, payoutForDuration }
|
||||
function calculatePartialPayout(request, expiresAt, filledAt) {
|
||||
return (Number(expiresAt) - Number(filledAt)) * pricePerSlotPerSecond(request)
|
||||
}
|
||||
|
||||
function calculateBalance(balance, reward) {
|
||||
return BigInt(balance) + BigInt(reward)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
maxPrice,
|
||||
pricePerSlotPerSecond,
|
||||
payoutForDuration,
|
||||
calculatePartialPayout,
|
||||
calculateBalance,
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
const { Assertion } = require("chai")
|
||||
const { currentTime } = require("./evm")
|
||||
|
||||
const RequestState = {
|
||||
New: 0,
|
||||
@ -10,13 +9,13 @@ const RequestState = {
|
||||
}
|
||||
|
||||
const SlotState = {
|
||||
Free: 0,
|
||||
Filled: 1,
|
||||
Finished: 2,
|
||||
Failed: 3,
|
||||
Paid: 4,
|
||||
Cancelled: 5,
|
||||
Repair: 6,
|
||||
Free: 0n,
|
||||
Filled: 1n,
|
||||
Finished: 2n,
|
||||
Failed: 3n,
|
||||
Paid: 4n,
|
||||
Cancelled: 5n,
|
||||
Repair: 6n,
|
||||
}
|
||||
|
||||
function enableRequestAssertions() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user