GitHub Action helpers libs

pull/3274/head
Praise Disu 2 years ago committed by Aniket
parent 9efa9dd973
commit af39d46e1d
  1. 0
      libs/ghaction-helper/.eslintrc
  2. 0
      libs/ghaction-helper/.npmignore
  3. 0
      libs/ghaction-helper/README.md
  4. 32
      libs/ghaction-helper/package.json
  5. 25
      libs/ghaction-helper/src/artifacts-helper.ts
  6. 3
      libs/ghaction-helper/src/chai.ts
  7. 8
      libs/ghaction-helper/src/ethers.ts
  8. 2
      libs/ghaction-helper/src/index.ts
  9. 70
      libs/ghaction-helper/src/methods.ts
  10. 27
      libs/ghaction-helper/src/signer.ts
  11. 0
      libs/ghaction-helper/tsconfig.json
  12. 0
      libs/ghaction-helper/tsconfig.lib.json
  13. 40
      libs/ghaction/package.json
  14. 22
      libs/ghaction/src/artefacts-helper.ts
  15. 9
      libs/ghaction/src/ethers.ts
  16. 2
      libs/ghaction/src/index.ts
  17. 2
      package.json

@ -0,0 +1,32 @@
{
"name": "@remix-project/ghaction-helper",
"version": "0.1.0-dev",
"description": "Solidity Tests GitHub Action Helper",
"main": "dist/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ethereum/remix-project.git"
},
"keywords": [],
"author": "@ioedeveloper",
"license": "ISC",
"bugs": {
"url": "https://github.com/ethereum/remix-project/issues"
},
"homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": {
"@remix-project/remix-solidity": "^0.5.6",
"@types/chai": "^4.3.4",
"typescript": "^4.9.3"
},
"dependencies": {
"@ethereum-waffle/chai": "^3.4.4",
"chai": "^4.3.7",
"ethers": "^5.7.2",
"ganache": "^7.5.0"
}
}

@ -0,0 +1,25 @@
import { CompilationResult } from '@remix-project/remix-solidity'
//@ts-ignore
import * as fs from 'fs/promises'
import * as path from 'path'
declare global {
const remixContractArtifactsPath: string
}
export async function getArtifactsByContractName (contractIdentifier: string) {
//@ts-ignore
const contractArtifacts = await fs.readdir(global.remixContractArtifactsPath)
let contract
for (const artifactFile of contractArtifacts) {
//@ts-ignore
const artifact = await fs.readFile(path.join(global.remixContractArtifactsPath, artifactFile), 'utf-8')
const artifactJSON: CompilationResult = JSON.parse(artifact)
const contractFullPath = (Object.keys(artifactJSON.contracts!)).find((contractName) => artifactJSON.contracts![contractName] && artifactJSON.contracts![contractName][contractIdentifier])
contract = contractFullPath ? artifactJSON.contracts![contractFullPath!][contractIdentifier] : undefined
if (contract) break
}
return contract
}

@ -3,5 +3,6 @@ import { waffleChai } from '@ethereum-waffle/chai'
chai.use(waffleChai) chai.use(waffleChai)
// @ts-ignore
export * from 'chai' export * from 'chai'
export { chai } export { chai }

@ -0,0 +1,8 @@
// @ts-nocheck
import { ethers } from 'ethers'
import * as hhEtherMethods from './methods'
for(const method in hhEtherMethods) Object.defineProperty(ethers, method, { value: hhEtherMethods[method]})
export * from 'ethers'
export { ethers }

@ -0,0 +1,2 @@
export * from './chai'
export * from './ethers'

@ -1,16 +1,24 @@
// @ts-ignore
import { ethers } from "ethers" import { ethers } from "ethers"
import { getArtefactsByContractName } from './artefacts-helper' //@ts-ignore
import * as ganache from "ganache"
import { getArtifactsByContractName } from './artifacts-helper'
import { SignerWithAddress } from './signer' import { SignerWithAddress } from './signer'
declare global { declare global {
const ganacheProvider: any const ganacheProvider: any
} }
const isFactoryOptions = (signerOrOptions) => { const initializeProvider = () => {
//@ts-ignore
global.ganacheProvider = ganache.provider({ logging: { quiet: true } })
}
const isFactoryOptions = (signerOrOptions: any) => {
if (!signerOrOptions || signerOrOptions === undefined || signerOrOptions instanceof ethers.Signer) return false if (!signerOrOptions || signerOrOptions === undefined || signerOrOptions instanceof ethers.Signer) return false
return true return true
} }
const isArtifact = (artifact) => { const isArtifact = (artifact: any) => {
const { const {
contractName, contractName,
sourceName, sourceName,
@ -32,11 +40,12 @@ const isArtifact = (artifact) => {
) )
} }
function linkBytecode(artifact, libraries) { function linkBytecode(artifact: any, libraries: any) {
let bytecode = artifact.bytecode let bytecode = artifact.bytecode
for (const { sourceName, libraryName, address } of libraries) { for (const { sourceName, libraryName, address } of libraries) {
const linkReferences = artifact.linkReferences[sourceName][libraryName] const linkReferences = artifact.linkReferences[sourceName][libraryName]
for (const { start, length } of linkReferences) { for (const { start, length } of linkReferences) {
bytecode = bytecode =
bytecode.substr(0, 2 + start * 2) + bytecode.substr(0, 2 + start * 2) +
@ -48,9 +57,10 @@ function linkBytecode(artifact, libraries) {
return bytecode return bytecode
} }
const collectLibrariesAndLink = async (artifact, libraries) => { const collectLibrariesAndLink = async (artifact: any, libraries: any) => {
const neededLibraries = [] const neededLibraries = []
for (const [sourceName, sourceLibraries] of Object.entries(artifact.linkReferences)) { for (const [sourceName, sourceLibraries] of Object.entries(artifact.linkReferences)) {
// @ts-ignore
for (const libName of Object.keys(sourceLibraries)) { for (const libName of Object.keys(sourceLibraries)) {
neededLibraries.push({ sourceName, libName }) neededLibraries.push({ sourceName, libName })
} }
@ -58,6 +68,7 @@ const collectLibrariesAndLink = async (artifact, libraries) => {
const linksToApply = new Map() const linksToApply = new Map()
for (const [linkedLibraryName, linkedLibraryAddress] of Object.entries(libraries)) { for (const [linkedLibraryName, linkedLibraryAddress] of Object.entries(libraries)) {
// @ts-ignore
if (!ethers.utils.isAddress(linkedLibraryAddress)) { if (!ethers.utils.isAddress(linkedLibraryAddress)) {
throw new Error( throw new Error(
`You tried to link the contract ${artifact.contractName} with the library ${linkedLibraryName}, but provided this invalid address: ${linkedLibraryAddress}` `You tried to link the contract ${artifact.contractName} with the library ${linkedLibraryName}, but provided this invalid address: ${linkedLibraryAddress}`
@ -136,11 +147,12 @@ const collectLibrariesAndLink = async (artifact, libraries) => {
) )
} }
// @ts-ignore
return linkBytecode(artifact, [...linksToApply.values()]) return linkBytecode(artifact, [...linksToApply.values()])
} }
// Convert output.contracts.<filename>.<contractName> in Artifact object compatible form // Convert output.contracts.<filename>.<contractName> in Artifact object compatible form
const resultToArtifact = (result) => { const resultToArtifact = (result: any) => {
const { fullyQualifiedName, artefact } = result const { fullyQualifiedName, artefact } = result
return { return {
contractName: fullyQualifiedName.split(':')[1], contractName: fullyQualifiedName.split(':')[1],
@ -154,15 +166,17 @@ const resultToArtifact = (result) => {
} }
const getContractFactory = async (contractNameOrABI: ethers.ContractInterface, bytecode?: string, signerOrOptions = null) => { const getContractFactory = async (contractNameOrABI: ethers.ContractInterface, bytecode?: string, signerOrOptions = null) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
if (bytecode && contractNameOrABI) { if (bytecode && contractNameOrABI) {
return new ethers.ContractFactory(contractNameOrABI, bytecode, signerOrOptions || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner()) return new ethers.ContractFactory(contractNameOrABI, bytecode, signerOrOptions || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner())
} else if (typeof contractNameOrABI === 'string') { } else if (typeof contractNameOrABI === 'string') {
const contract = await getArtefactsByContractName(contractNameOrABI) const contract = await getArtifactsByContractName(contractNameOrABI)
if (contract) { if (contract) {
return new ethers.ContractFactory(contract.abi, contract.evm.bytecode.object, signerOrOptions || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner()) return new ethers.ContractFactory(contract.abi, contract.evm.bytecode.object, signerOrOptions || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner())
} else { } else {
throw new Error('Contract artefacts not found') throw new Error('Contract artifacts not found')
} }
} else { } else {
throw new Error('Invalid contract name or ABI provided') throw new Error('Invalid contract name or ABI provided')
@ -170,24 +184,26 @@ const getContractFactory = async (contractNameOrABI: ethers.ContractInterface, b
} }
const getContractAt = async (contractNameOrABI: ethers.ContractInterface, address: string, signer = null) => { const getContractAt = async (contractNameOrABI: ethers.ContractInterface, address: string, signer = null) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
const provider = new ethers.providers.Web3Provider(ganacheProvider) const provider = new ethers.providers.Web3Provider(ganacheProvider)
if(typeof contractNameOrABI === 'string') { if(typeof contractNameOrABI === 'string') {
try { const result = await getArtifactsByContractName(contractNameOrABI)
const result = await getArtefactsByContractName(contractNameOrABI)
if (result) {
if (result) { return new ethers.Contract(address, result.abi, signer || provider.getSigner())
return new ethers.Contract(address, result.abi, signer || provider.getSigner()) } else {
} else { throw new Error('Contract artifacts not found')
throw new Error('Contract artefacts not found') }
}
} catch(e) { throw e }
} else { } else {
return new ethers.Contract(address, contractNameOrABI, signer || provider.getSigner()) return new ethers.Contract(address, contractNameOrABI, signer || provider.getSigner())
} }
} }
const getSigner = async (address: string) => { const getSigner = async (address: string) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
const provider = new ethers.providers.Web3Provider(ganacheProvider) const provider = new ethers.providers.Web3Provider(ganacheProvider)
const signer = provider.getSigner(address) const signer = provider.getSigner(address)
@ -195,15 +211,17 @@ const getSigner = async (address: string) => {
} }
const getSigners = async () => { const getSigners = async () => {
try { //@ts-ignore
const provider = new ethers.providers.Web3Provider(ganacheProvider) if (!global.ganacheProvider) initializeProvider()
const accounts = await provider.listAccounts() const provider = new ethers.providers.Web3Provider(ganacheProvider)
const accounts = await provider.listAccounts()
return await Promise.all( accounts.map((account) => getSigner(account))) return await Promise.all( accounts.map((account: any) => getSigner(account)))
} catch(err) { throw err }
} }
const getContractFactoryFromArtifact = async (artifact, signerOrOptions = null) => { const getContractFactoryFromArtifact = async (artifact: any, signerOrOptions: { signer: any, libraries: any }) => {
//@ts-ignore
if (!global.ganacheProvider) initializeProvider()
let libraries = {} let libraries = {}
let signer let signer
@ -228,10 +246,10 @@ If you want to call a contract using ${artifact.contractName} as its interface u
} }
const linkedBytecode = await collectLibrariesAndLink(artifact, libraries) const linkedBytecode = await collectLibrariesAndLink(artifact, libraries)
return new ethers.ContractFactory(artifact.abi, linkedBytecode || artifact.bytecode, signer || (new ethers.providers.Web3Provider(web3Provider)).getSigner()) return new ethers.ContractFactory(artifact.abi, linkedBytecode || artifact.bytecode, signer || (new ethers.providers.Web3Provider(ganacheProvider)).getSigner())
} }
const getContractAtFromArtifact = async (artifact, address, signerOrOptions = null) => { const getContractAtFromArtifact = async (artifact: any, address: string, signerOrOptions = null) => {
if (!isArtifact(artifact)) { if (!isArtifact(artifact)) {
throw new Error( throw new Error(
`You are trying to create a contract factory from an artifact, but you have not passed a valid artifact parameter.` `You are trying to create a contract factory from an artifact, but you have not passed a valid artifact parameter.`
@ -241,4 +259,4 @@ const getContractAtFromArtifact = async (artifact, address, signerOrOptions = nu
return await getContractAt(artifact.abi, address, signerOrOptions) return await getContractAt(artifact.abi, address, signerOrOptions)
} }
export { getContractAtFromArtifact, getContractFactoryFromArtifact, getSigners, getSigner, getContractAt, getContractFactory } export { getContractAtFromArtifact, getContractFactoryFromArtifact, getSigners, getSigner, getContractAt, getContractFactory }

@ -1,11 +1,22 @@
// @ts-ignore
import { ethers } from "ethers" import { ethers } from "ethers"
export class SignerWithAddress extends ethers.Signer { export class SignerWithAddress extends ethers.Signer {
static async create(signer) { address: string
_signer: {
provider: any
signTransaction: (transaction: any) => any,
signMessage: (message: string) => any,
sendTransaction: (transaction: any) => any,
connect: (provider: any) => any,
_signTypedData: (...params: any) => any
}
provider: any
static async create(signer: any) {
return new SignerWithAddress(await signer.getAddress(), signer) return new SignerWithAddress(await signer.getAddress(), signer)
} }
constructor(address, _signer) { constructor(address: string, _signer: any) {
super() super()
this.address = address this.address = address
this._signer = _signer this._signer = _signer
@ -16,27 +27,27 @@ export class SignerWithAddress extends ethers.Signer {
return this.address return this.address
} }
signMessage(message){ signMessage(message: string){
return this._signer.signMessage(message) return this._signer.signMessage(message)
} }
signTransaction(transaction) { signTransaction(transaction: any) {
return this._signer.signTransaction(transaction) return this._signer.signTransaction(transaction)
} }
sendTransaction(transaction) { sendTransaction(transaction: any) {
return this._signer.sendTransaction(transaction) return this._signer.sendTransaction(transaction)
} }
connect(provider) { connect(provider: any) {
return new SignerWithAddress(this.address, this._signer.connect(provider)) return new SignerWithAddress(this.address, this._signer.connect(provider))
} }
_signTypedData(...params) { _signTypedData(...params: any) {
return this._signer._signTypedData(...params) return this._signer._signTypedData(...params)
} }
toJSON() { toJSON() {
return `<SignerWithAddress ${this.address}>` return `<SignerWithAddress ${this.address}>`
} }
} }

@ -1,40 +0,0 @@
{
"name": "@remix-project/ghaction",
"version": "0.1.0",
"description": "Tools to help with github actions for running solidity tests",
"main": "src/index.js",
"types": "src/index.d.ts",
"contributors": [
{
"name": "David Disu",
"email": "daviddisu8@gmail.com"
}
],
"dependencies": {
"ethers": "^5.7.2",
"ganache": "^7.5.0",
"chai": "^4.3.7",
"@remix-project/remix-solidity": "^0.5.5",
"@ethereum-waffle/chai": "^3.4.4"
},
"devDependencies": {
"typescript": "^3.7.4"
},
"scripts": {
"build": "tsc"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ethereum/remix-project.git"
},
"author": "Remix Team",
"license": "MIT",
"bugs": {
"url": "https://github.com/ethereum/remix-project/issues"
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/ghaction#readme",
"typings": "src/index.d.ts"
}

@ -1,22 +0,0 @@
import { CompilationResult } from '@remix-project/remix-solidity'
import * as fs from 'fs/promises'
import * as path from 'path'
declare global {
const remixContractArtefactsPath: string
}
export async function getArtefactsByContractName (contractIdentifier: string) {
const contractArtefacts = await fs.readdir(global.remixContractArtefactsPath)
let contract
for (const artefactFile of contractArtefacts) {
const artefact = await fs.readFile(path.join(global.remixContractArtefactsPath, artefactFile), 'utf-8')
const artefactJSON: CompilationResult = JSON.parse(artefact)
const contractFullPath = (Object.keys(artefactJSON.contracts!)).find((contractName) => artefactJSON.contracts![contractName] && artefactJSON.contracts![contractName][contractIdentifier])
contract = contractFullPath ? artefactJSON.contracts![contractFullPath!][contractIdentifier] : undefined
if (contract) break
}
return contract
}

@ -1,9 +0,0 @@
import { ethers } from 'ethers'
import * as ganache from 'ganache'
import * as hhEtherMethods from './methods'
global.ganacheProvider = ganache.provider({ logging: { quiet: true } })
for(const method in hhEtherMethods) Object.defineProperty(ethers, method, { value: hhEtherMethods[method]})
export * from 'ethers'
export { ethers }

@ -1,2 +0,0 @@
export * from './chai'
export * from './ethers'

@ -45,7 +45,7 @@
"workspace-schematic": "nx workspace-schematic", "workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph", "dep-graph": "nx dep-graph",
"help": "nx help", "help": "nx help",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,solidity-unit-testing,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs,remix-ui-panel,remix-ui-run-tab,remix-ui-permission-handler,remix-ui-search,remix-ui-file-decorators,remix-ui-tooltip-popup", "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,solidity-unit-testing,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs,remix-ui-panel,remix-ui-run-tab,remix-ui-permission-handler,remix-ui-search,remix-ui-file-decorators,remix-ui-tooltip-popup,ghaction-helper",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd", "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remix-ws-templates,remixd",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-tests,remix-url-resolver,remixd", "test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-tests,remix-url-resolver,remixd",
"publish:libs": "yarn run build:libs && lerna publish --skip-git && yarn run bumpVersion:libs", "publish:libs": "yarn run build:libs && lerna publish --skip-git && yarn run bumpVersion:libs",

Loading…
Cancel
Save