Skip to content

Commit

Permalink
chore: remove Python requirement for contracts development. (#1144)
Browse files Browse the repository at this point in the history
  • Loading branch information
raulk authored Sep 24, 2024
1 parent cdc9661 commit 294531c
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 220 deletions.
20 changes: 6 additions & 14 deletions contracts/Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Targets that are commands.
COMMANDS := deploy-stack gen compile-abi rust-binding slither lint fmt deps build \
test install-dev install-npm-package install-eth-abi storage clean coverage \
prepare build-selector-library forge
prepare forge

# Targets that are prerequisite commands.
PREREQ_COMMANDS := pnpm

# Targets that are not commands.
NON_COMMANDS := node_modules
NON_COMMANDS := node_modules test/helpers/SelectorLibrary.sol

# Declare commands and prerequisite commands as phony targets.
.PHONY: $(COMMANDS) $(PREREQ_COMMANDS)
Expand Down Expand Up @@ -77,17 +77,9 @@ build: node_modules | forge
forge build
FOUNDRY_SRC=sdk forge build

test: node_modules | forge
test: node_modules test/helpers/SelectorLibrary.sol | forge
forge test -vvv --ffi

install-dev: install-npm-package install-eth-abi

install-npm-package: node_modules
pnpm install --save-dev

install-eth-abi:
curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py && rm get-pip.py && python3 -m pip install eth_abi

storage:
rm -rf ./cache
rm -rf ./cache_hardhat
Expand All @@ -108,10 +100,10 @@ coverage: node_modules | forge
fi
./tools/check_coverage.sh

prepare: build-selector-library fmt lint test slither
prepare: test/helpers/SelectorLibrary.sol fmt lint test slither

build-selector-library: | forge
python3 scripts/python/build_selector_library.py
test/helpers/SelectorLibrary.sol: | forge
pnpm exec hardhat gen-selector-library
pnpm exec prettier -w test/helpers/SelectorLibrary.sol

# Forge is used by the ipc-solidity-actors compilation steps.
Expand Down
30 changes: 19 additions & 11 deletions contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import './extensions'

// Load environment variables from .env file.
import { config as dotenvConfig } from 'dotenv'

dotenvConfig({ path: './.env' })

// Import our tasks.
Expand All @@ -29,17 +30,7 @@ const networkDefinition = (chainId: number, url: string) => ({
saveDeployments: true,
})

const config: HardhatUserConfig = {
defaultNetwork: 'calibrationnet',
networks: {
// Static networks.
mainnet: networkDefinition(314, 'https://api.node.glif.io/rpc/v1'),
calibrationnet: networkDefinition(314159, 'https://api.calibration.node.glif.io/rpc/v1'),
localnet: networkDefinition(31415926, 'http://localhost:8545'),
// Auto uses RPC_URL provided by the user, and an optional CHAIN_ID.
// If provided, Hardhat will assert that the chain ID matches the one returned by the RPC.
auto: networkDefinition(parseInt(process.env.CHAIN_ID, 10), process.env.RPC_URL!),
},
let config: HardhatUserConfig = {
solidity: {
compilers: [
{
Expand Down Expand Up @@ -67,4 +58,21 @@ const config: HardhatUserConfig = {
},
}

// Only add the network configurations if we have a private key.
// Some targets don't require networks, e.g. gen-selector-library.
if (process.env.PRIVATE_KEY) {
config = Object.assign(config, {
defaultNetwork: 'calibrationnet',
networks: {
// Static networks.
mainnet: networkDefinition(314, 'https://api.node.glif.io/rpc/v1'),
calibrationnet: networkDefinition(314159, 'https://api.calibration.node.glif.io/rpc/v1'),
localnet: networkDefinition(31415926, 'http://localhost:8545'),
// Auto uses RPC_URL provided by the user, and an optional CHAIN_ID.
// If provided, Hardhat will assert that the chain ID matches the one returned by the RPC.
auto: networkDefinition(parseInt(process.env.CHAIN_ID, 10), process.env.RPC_URL!),
},
})
}

export default config
122 changes: 0 additions & 122 deletions contracts/scripts/python/build_selector_library.py

This file was deleted.

73 changes: 73 additions & 0 deletions contracts/tasks/gen-selector-library.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { task } from 'hardhat/config'
import '@nomiclabs/hardhat-ethers'
import * as fs from 'fs'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { selectors } from './lib'

task('gen-selector-library', 'Generates a Solidity library with contract selectors for tests').setAction(
async (_args, hre: HardhatRuntimeEnvironment) => {
await hre.run('compile')

// ridiculously, this appears to be the only way to get hardhat to compile a specific subtree
// we are only updating the in-memory representation of the config, so it won't write this value out to disk
// be careful if you compose this task with other tasks in larger scripts!
hre.config.paths.sources = './test/mocks'
await hre.run('compile')

const contracts: string[] = [
'OwnershipFacet',
'DiamondCutFacet',
'DiamondLoupeFacet',
'GatewayGetterFacet',
'GatewayManagerFacet',
'GatewayMessengerFacet',
'CheckpointingFacet',
'TopDownFinalityFacet',
'XnetMessagingFacet',
'SubnetActorGetterFacet',
'SubnetActorManagerFacet',
'SubnetActorPauseFacet',
'SubnetActorRewardFacet',
'SubnetActorCheckpointingFacet',
'RegisterSubnetFacet',
'SubnetGetterFacet',
'SubnetActorMock',
]

const resolveSelectors = async (contractName: string) => {
console.log(`Resolving selectors for ${contractName}...`)
const artifact = await hre.artifacts.readArtifact(contractName)
const iface = new hre.ethers.utils.Interface(artifact.abi)
const encodedSelectors = hre.ethers.utils.defaultAbiCoder
.encode(['bytes4[]'], [selectors({ interface: iface })])
.slice(2)
return [contractName, encodedSelectors]
}

const allSelectors = Object.fromEntries(await Promise.all(contracts.map(resolveSelectors)))

// Codegen.
let code = `// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.19;
library SelectorLibrary {
function resolveSelectors(string memory facetName) public pure returns (bytes4[] memory facetSelectors) {`

for (const [contractName, selector] of Object.entries(allSelectors)) {
code += `
if (keccak256(abi.encodePacked(facetName)) == keccak256(abi.encodePacked("${contractName}"))) {
return abi.decode(hex"${selector}", (bytes4[]));
}`
}

code += `
revert(string.concat("Selectors not found for facet: ", facetName));
}
}
`
// Write the generated code to a file.
const outputPath = 'test/helpers/SelectorLibrary.sol'
fs.writeFileSync(outputPath, code)
console.log(`Selector library written to ${outputPath}`)
},
)
1 change: 1 addition & 0 deletions contracts/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ import './deploy-registry'
import './deploy'
import './upgrade'
import './validator-gater'
import './gen-selector-library'
2 changes: 1 addition & 1 deletion contracts/tasks/lib/deployments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class Deployments {
(contract: Contract) => contract.address,
)
}

get contracts(): { [key: string]: Contract } {
return this._contracts
}
Expand Down
8 changes: 6 additions & 2 deletions contracts/tasks/lib/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {Contract} from "ethers";
import {Interface} from "ethers/lib/utils";

export function selectors(contract: Contract) {
interface ContractLike {
interface: Interface;
}

export function selectors(contract: ContractLike) {
return Object.keys(contract.interface.functions)
.filter((sig) => sig !== 'init(bytes)')
.map((sig) => contract.interface.getSighash(sig))
Expand Down
Loading

0 comments on commit 294531c

Please sign in to comment.