@eth-乐观主义/smock
smock 是一种可以生成模拟固态合同(用于测试)的通用软件包. smock 钩入一 ethereumjs-vm 实例,以便模拟合同函数可以完全用 JavaScript 写入. smock 目前仅支持 哈达特,但将扩展用于支持其他测试框架.
在VM一级钩入的一些好处:
- 不需要因为嘲笑而部署任何特别合同!
- 所有通话都是同步的.
- 在返回值(返回一个函数)中执行任意的javascript逻辑.
- 这听起来很酷.
smock 还载有 smoddit,可以修改合同的内部存储。 我们发现这在单个合同内发生许多相互作用(通常是为了节省气体)的情况下相当有用.
安装
你可以轻松安装 smock 通过 npm数字 :
npm install @eth-optimism/smock
或者通过 yarn数字 :
yarn add @eth-optimism/smock
关于使用的说明 smoddit
smoddit 需要访问智能合同的内部存储布局。 团结编译器通过 storageLayout 旗帜,您需要启用 您的硬帽子配置.
这里有个例子 hardhat.config.ts 显示如何导入插件 :
// hardhat.config.ts
import { HardhatUserConfig } from 'hardhat/config'
const config: HardhatUserConfig = {
...,
solidity: {
version: '0.7.0',
settings: {
outputSelection: {
"*": {
"*": ["storageLayout"],
},
},
}
},
}
export default config
API 密码
职能
smockit
导入
import { smockit } from '@eth-optimism/smock'
签署
const smockit = async (
spec: ContractInterface | Contract | ContractFactory,
opts: {
provider?: any,
address?: string,
},
): Promise<MockContract>
smoddit
导入
import { smoddit } from '@eth-optimism/smock'
签署
const smoddit = async (
name: string,
signer?: any
): Promise<ModifiableContractFactory>
类型
smockit
MockContract
interface MockContract extends ethers.Contract {
smocked: {
[functionName: string]: MockContractFunction
}
// A wallet you can use to send transactions *from* a smocked contract
wallet: ethers.Signer
}
MockContractFunction
interface MockContractFunction {
calls: string[]
will: {
return: {
(): void
with: (returnValue?: MockReturnValue) => void
}
revert: {
(): void
with: (revertValue?: string) => void
}
resolve: 'return' | 'revert'
}
}
MockReturnValue
export type MockReturnValue =
| string
| Object
| any[]
| ((...params: any[]) => MockReturnValue)
smoddit
ModifiableContractFactory
interface ModifiableContractFactory extends ethers.ContractFactory {
deploy: (...args: any[]) => Promise<ModifiableContract>
}
ModifiableContract
interface ModifiableContract extends ethers.Contract {
smodify: {
put: (storage: any) => Promise<void>
}
}
实例(嘲笑)
通过 ethers.Contract
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return.with('Some return value!')
console.log(await MyMockContract.myFunction()) // 'Some return value!'
请求数
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
const MyOtherContractFactory = await ethers.getContractFactory('MyOtherContract')
const MyOtherContract = await MyOtherContract.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return.with('Some return value!')
// Assuming that MyOtherContract.myOtherFunction calls MyContract.myFunction.
await MyOtherContract.myOtherFunction()
console.log(MyMockContract.smocked.myFunction.calls.length) // 1
调用数据
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
const MyOtherContractFactory = await ethers.getContractFactory('MyOtherContract')
const MyOtherContract = await MyOtherContract.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return.with('Some return value!')
// Assuming that MyOtherContract.myOtherFunction calls MyContract.myFunction with 'Hello World!'.
await MyOtherContract.myOtherFunction()
console.log(MyMockContract.smocked.myFunction.calls[0]) // 'Hello World!'
返回(w/o数据)
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return()
console.log(await MyMockContract.myFunction()) // []
正在返回 Struct
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return.with({
valueA: 'Some value',
valueB: 1234,
valueC: true
})
console.log(await MyMockContract.myFunction()) // ['Some value', 1234, true]
返回多阵列
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return.with([
[1234, 5678],
[4321, 8765]
])
console.log(await MyMockContract.myFunction()) // [ [1234, 5678], [4321, 8765] ]
返回函数
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return.with(() => {
return 'Some return value!'
})
console.log(await MyMockContract.myFunction()) // 'Some return value!'
返回函数(w/参数)
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.return.with((myFunctionArgument: string) => {
return myFunctionArgument
})
console.log(await MyMockContract.myFunction('Some return value!')) // 'Some return value!'
还原(w/o数据)
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.revert()
console.log(await MyMockContract.myFunction()) // Revert!
还原(w/数据)
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const MyContractFactory = await ethers.getContractFactory('MyContract')
const MyContract = await MyContractFactory.deploy(...)
// Smockit!
const MyMockContract = await smockit(MyContract)
MyMockContract.smocked.myFunction.will.revert.with('0x1234')
console.log(await MyMockContract.myFunction('Some return value!')) // Revert!
B. 从毁损的合同发送交易
import { ethers } from 'hardhat'
import { smockit } from '@eth-optimism/smock'
const myContractFactory = await ethers.getContractFactory('MyContract')
const myContract = await myContractFactory.deploy(...)
// Smockit!
const mock = await smockit('AnotherContract')
await myContract.connect(mock.wallet).doSomeFunction() // msg.sender == mock.address
实例( smoddit)
创建可修改的合同
import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'
// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)
正在修改 a uint256
import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'
// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)
await MyModifiableContract.smodify.put({
myInternalUint256: 1234
})
console.log(await MyMockContract.getMyInternalUint256()) // 1234
修改字符串
import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'
// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)
await MyModifiableContract.smodify.put({
myInternalStruct: {
valueA: 1234,
valueB: true
}
})
console.log(await MyMockContract.getMyInternalStruct()) // { valueA: 1234, valueB: true }
修改绘图
import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'
// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)
await MyModifiableContract.smodify.put({
myInternalMapping: {
1234: 5678
}
})
console.log(await MyMockContract.getMyInternalMappingValue(1234)) // 5678
修改嵌入式映射
import { ethers } from 'hardhat'
import { smoddit } from '@eth-optimism/smock'
// Smoddit!
const MyModifiableContractFactory = await smoddit('MyContract')
const MyModifiableContract = await MyModifiableContractFactory.deploy(...)
await MyModifiableContract.smodify.put({
myInternalNestedMapping: {
1234: {
4321: 5678
}
}
})
console.log(await MyMockContract.getMyInternalNestedMappingValue(1234, 4321)) // 5678