Skip to content

Commit

Permalink
ci: set up eslint
Browse files Browse the repository at this point in the history
  • Loading branch information
nattb8 committed May 28, 2024
1 parent 45b2d11 commit 15248f5
Show file tree
Hide file tree
Showing 15 changed files with 5,656 additions and 127 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,33 @@ jobs:
VALIDATE_JAVASCRIPT_STANDARD: false
VALIDATE_TYPESCRIPT_ES: false
VALIDATE_TYPESCRIPT_STANDARD: false

##################################
# Run eslint against json-server #
##################################
- name: Install packages for json-server
working-directory: ./json-server
run: yarn install
- name: Run eslint against json-server
working-directory: ./json-server
run: yarn lint

###################################
# Run eslint against mint-backend #
###################################
- name: Install packages for mint-backend
working-directory: ./mint-backend
run: yarn install
- name: Run eslint against mint-backend
working-directory: ./mint-backend
run: yarn lint

################################
# Run eslint against contracts #
################################
- name: Install packages for contracts
working-directory: ./contracts
run: yarn install
- name: Run eslint against contracts
working-directory: ./contracts
run: yarn lint
25 changes: 13 additions & 12 deletions contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
/* eslint-disable import/no-extraneous-dependencies */
import { HardhatUserConfig } from 'hardhat/config';
import '@nomicfoundation/hardhat-toolbox';

import * as dotenv from 'dotenv';

dotenv.config();

const config: HardhatUserConfig = {
solidity: {
version: "0.8.19",
version: '0.8.19',
settings: {
optimizer: {
enabled: true,
Expand All @@ -17,28 +18,28 @@ const config: HardhatUserConfig = {
},
networks: {
immutableZkevmTestnet: {
url: "https://rpc.testnet.immutable.com",
url: 'https://rpc.testnet.immutable.com',
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
},
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY,
customChains: [
{
network: "immutableZkevmTestnet",
network: 'immutableZkevmTestnet',
chainId: 13473,
urls: {
apiURL: "https://explorer.testnet.immutable.com/api",
browserURL: "https://explorer.testnet.immutable.com"
}
}
]
apiURL: 'https://explorer.testnet.immutable.com/api',
browserURL: 'https://explorer.testnet.immutable.com',
},
},
],
},
sourcify: {
// Disabled by default
// Doesn't need an API key
enabled: true
}
enabled: true,
},
};

export default config;
13 changes: 11 additions & 2 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"clean": "npx hardhat clean",
"test": "npx hardhat test",
"compile": "npx hardhat compile",
"deploy": "npx hardhat run --network immutableZkevmTestnet scripts/deploy.ts"
"deploy": "npx hardhat run --network immutableZkevmTestnet scripts/deploy.ts",
"lint": "eslint ."
},
"author": "Immutable",
"license": "MIT",
Expand All @@ -29,7 +30,15 @@
"solidity-coverage": "^0.8.11",
"ts-node": "^10.9.2",
"typechain": "^8.3.2",
"typescript": "^5.4.2"
"eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"typescript": "^5.4.2",
"typescript-eslint": "^7.11.0"
},
"dependencies": {
"@imtbl/contracts": "^2.2.6",
Expand Down
4 changes: 2 additions & 2 deletions contracts/scripts/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ethers } from "hardhat";
import { ethers } from 'hardhat'; // eslint-disable-line import/no-extraneous-dependencies

async function main() {
// Load the Immutable Runner Tokencontract and get the contract factory
const contractFactory = await ethers.getContractFactory('RunnerToken');

// Deploy the contract to the zkEVM network
const contract = await contractFactory.deploy(
'YOUR_IMMUTABLE_RUNNER_SKIN_CONTRACT_ADDRESS' // Immutable Runner Skin contract address
'YOUR_IMMUTABLE_RUNNER_SKIN_CONTRACT_ADDRESS', // Immutable Runner Skin contract address
);

console.log('Contract deployed to:', await contract.getAddress());
Expand Down
77 changes: 40 additions & 37 deletions contracts/test/RunnerToken.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ethers } from "hardhat";
import { expect } from "chai";
import { RunnerToken, OperatorAllowlist__factory, RunnerToken__factory, ImmutableERC721, ImmutableERC721__factory } from "../typechain-types";
import { ethers } from 'hardhat';
import { expect } from 'chai';
// eslint-disable-next-line import/extensions
import { RunnerToken, OperatorAllowlist__factory, RunnerToken__factory, ImmutableERC721, ImmutableERC721__factory } from '../typechain-types';

describe("RunnerToken", function () {
describe('RunnerToken', function () {
let contract: RunnerToken;
let skinContract: ImmutableERC721;

Expand All @@ -12,27 +13,27 @@ describe("RunnerToken", function () {

// deploy OperatorAllowlist contract
const OperatorAllowlist = await ethers.getContractFactory(
"OperatorAllowlist"
'OperatorAllowlist',
) as OperatorAllowlist__factory;
const operatorAllowlist = await OperatorAllowlist.deploy(owner.address);

// deploy RunnerSkin contract
const ImmutableERC721 = await ethers.getContractFactory("ImmutableERC721") as ImmutableERC721__factory;
skinContract = await ImmutableERC721.deploy(
const ImmutableERC721Contract = await ethers.getContractFactory('ImmutableERC721') as ImmutableERC721__factory;
skinContract = await ImmutableERC721Contract.deploy(
owner.address, // owner
"Immutable Runner Skin", // name
"IMRS", // symbol
"https://immutable.com/", // baseURI
"https://immutable.com/", // contractURI
'Immutable Runner Skin', // name
'IMRS', // symbol
'https://immutable.com/', // baseURI
'https://immutable.com/', // contractURI
await operatorAllowlist.getAddress(), // operator allowlist contract
owner.address, // royalty recipient
2000 // fee numerator
2000, // fee numerator
);
await skinContract.waitForDeployment();

// deploy RunnerToken contract
const RunnerToken = await ethers.getContractFactory("RunnerToken") as RunnerToken__factory;
contract = await RunnerToken.deploy(await skinContract.getAddress());
const RunnerTokenContract = await ethers.getContractFactory('RunnerToken') as RunnerToken__factory;
contract = await RunnerTokenContract.deploy(await skinContract.getAddress());
await contract.waitForDeployment();

// grant owner the minter role
Expand All @@ -41,12 +42,12 @@ describe("RunnerToken", function () {
await skinContract.grantMinterRole(await contract.getAddress());
});

it("Should be deployed with the correct arguments", async function () {
expect(await contract.name()).to.equal("Immutable Runner Token");
expect(await contract.symbol()).to.equal("IMR");
it('Should be deployed with the correct arguments', async function () {
expect(await contract.name()).to.equal('Immutable Runner Token');
expect(await contract.symbol()).to.equal('IMR');
});

it("Account with minter role should be able to mint tokens", async function () {
it('Account with minter role should be able to mint tokens', async function () {
const [owner, recipient] = await ethers.getSigners();

await contract.connect(owner).mint(recipient.address, 1);
Expand All @@ -56,17 +57,18 @@ describe("RunnerToken", function () {
expect(await contract.balanceOf(recipient.address)).to.equal(3);
});

it("Account without minter role should not be able to mint NFTs", async function () {
it('Account without minter role should not be able to mint NFTs', async function () {
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars
const [_, acc1] = await ethers.getSigners();
const minterRole = await contract.MINTER_ROLE();
await expect(
contract.connect(acc1).mint(acc1.address, 1)
contract.connect(acc1).mint(acc1.address, 1),
).to.be.revertedWith(
`AccessControl: account ${acc1.address.toLowerCase()} is missing role ${minterRole}`
`AccessControl: account ${acc1.address.toLowerCase()} is missing role ${minterRole}`,
);
});

it("Owner of tokens should be able to burn tokens", async function () {
it('Owner of tokens should be able to burn tokens', async function () {
const [owner, recipient] = await ethers.getSigners();

await contract.connect(owner).mint(recipient.address, 2);
Expand All @@ -76,7 +78,7 @@ describe("RunnerToken", function () {
expect(await contract.balanceOf(recipient.address)).to.equal(1);
});

it("Owner of tokens should not be able to burn tokens if not enough to burn", async function () {
it('Owner of tokens should not be able to burn tokens if not enough to burn', async function () {
const [owner, recipient] = await ethers.getSigners();

await contract.connect(owner).mint(recipient.address, 1);
Expand All @@ -86,22 +88,22 @@ describe("RunnerToken", function () {
expect(await contract.balanceOf(recipient.address)).to.equal(0);

await expect(
contract.connect(recipient).burn(1)
).to.be.revertedWith(`ERC20: burn amount exceeds balance`);
contract.connect(recipient).burn(1),
).to.be.revertedWith('ERC20: burn amount exceeds balance');
});

it("Others should not be able to burn others tokens", async function () {
it('Others should not be able to burn others tokens', async function () {
const [owner, acc1, recipient] = await ethers.getSigners();

await contract.connect(owner).mint(recipient.address, 2);
expect(await contract.balanceOf(recipient.address)).to.equal(2);

await expect(
contract.connect(acc1).burnFrom(recipient.address, 1)
).to.be.revertedWith(`ERC20: insufficient allowance`);
contract.connect(acc1).burnFrom(recipient.address, 1),
).to.be.revertedWith('ERC20: insufficient allowance');
});

it("Account with three tokens can craft skin", async function () {
it('Account with three tokens can craft skin', async function () {
const [owner, recipient] = await ethers.getSigners();

const threeTokens = 3n * (10n ** await contract.decimals());
Expand All @@ -114,19 +116,19 @@ describe("RunnerToken", function () {
expect(await skinContract.ownerOf(await skinContract.mintBatchByQuantityThreshold())).to.equal(recipient.address);
});

it("Account with not enough tokens should not be able to craft skin", async function () {
it('Account with not enough tokens should not be able to craft skin', async function () {
const [owner, recipient] = await ethers.getSigners();

const twoTokens = 2n * (10n ** await contract.decimals());
await contract.connect(owner).mint(recipient.address, twoTokens);
expect(await contract.balanceOf(recipient.address)).to.equal(twoTokens);

await expect(contract.connect(recipient).craftSkin()).to.be.revertedWith(
'ERC20: burn amount exceeds balance'
'ERC20: burn amount exceeds balance',
);
});

it("Token contract should not be able to craft skin without skin contract minter role", async function () {
it('Token contract should not be able to craft skin without skin contract minter role', async function () {
const [owner, recipient] = await ethers.getSigners();
await skinContract.revokeMinterRole(await contract.getAddress());

Expand All @@ -135,26 +137,27 @@ describe("RunnerToken", function () {
expect(await contract.balanceOf(recipient.address)).to.equal(threeTokens);

await expect(contract.connect(recipient).craftSkin()).to.be.revertedWith(
`AccessControl: account ${(await contract.getAddress()).toLowerCase()} is missing role ${await skinContract.MINTER_ROLE()}`
`AccessControl: account ${(await contract.getAddress()).toLowerCase()} is missing role ${await skinContract.MINTER_ROLE()}`,
);
expect(await contract.balanceOf(recipient.address)).to.equal(threeTokens);
});

it("Only admin account can grant minter role", async function () {
it('Only admin account can grant minter role', async function () {
const [owner, recipient] = await ethers.getSigners();

await contract.connect(owner).grantMinterRole(recipient.address);
expect(await contract.hasRole(await contract.MINTER_ROLE(), recipient.address)).to.equal(true);
});

it("Non-admin accounts cannot grant minter role", async function () {
it('Non-admin accounts cannot grant minter role', async function () {
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars
const [_, acc1, recipient] = await ethers.getSigners();
const adminRole = await contract.DEFAULT_ADMIN_ROLE();

await expect(
contract.connect(acc1).grantMinterRole(recipient.address)
contract.connect(acc1).grantMinterRole(recipient.address),
).to.be.revertedWith(
`AccessControl: account ${acc1.address.toLowerCase()} is missing role ${adminRole}`
`AccessControl: account ${acc1.address.toLowerCase()} is missing role ${adminRole}`,
);
});
});
8 changes: 6 additions & 2 deletions contracts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@
"strict": true,
"skipLibCheck": true
},
"include": ["./scripts"]
}
"include": [
"./scripts",
"./test",
"hardhat.config.ts"
]
}
Loading

0 comments on commit 15248f5

Please sign in to comment.