Commit a656f06b authored by smartcontracts's avatar smartcontracts Committed by GitHub

feat[smock]: add a wallet that be used to send transactions from a smock (#896)

* feat[smock]: add support for sending txs from mocks

* fix: remove unused imports

* chore: add changeset

* fix: readme errors

* Update packages/smock/README.md

* Update packages/smock/README.md
Co-authored-by: default avatarMaurelian <maurelian@protonmail.ch>
Co-authored-by: default avatarMaurelian <maurelian@protonmail.ch>
parent 2d352de8
---
'@eth-optimism/smock': patch
---
Adds a wallet object to smock contracts that can be used to send transactions
...@@ -51,40 +51,6 @@ const config: HardhatUserConfig = { ...@@ -51,40 +51,6 @@ const config: HardhatUserConfig = {
export default config export default config
``` ```
## Table of Contents
- [API](#api)
* [Functions](#functions)
+ [`smockit`](#-smockit-)
- [Import](#import)
- [Signature](#signature)
+ [`smoddit`](#-smoddit-)
- [Import](#import-1)
- [Signature](#signature-1)
* [Types](#types)
+ [`smockit`](#-smockit--1)
- [`MockContract`](#-mockcontract-)
- [`MockContractFunction`](#-mockcontractfunction-)
- [`MockReturnValue`](#-mockreturnvalue-)
+ [`smoddit`](#-smoddit--1)
- [`ModifiableContractFactory`](#-modifiablecontractfactory-)
- [`ModifiableContract`](#-modifiablecontract-)
- [Examples (smockit)](#examples--smockit-)
* [Via `ethers.Contract`](#via--etherscontract-)
* [Asserting Call Count](#asserting-call-count)
* [Asserting Call Data](#asserting-call-data)
* [Returning (w/o Data)](#returning--w-o-data-)
* [Returning a Struct](#returning-a-struct)
* [Returning a Function](#returning-a-function)
* [Returning a Function (w/ Arguments)](#returning-a-function--w--arguments-)
* [Reverting (w/o Data)](#reverting--w-o-data-)
* [Reverting (w/ Data)](#reverting--w--data-)
- [Examples (smoddit)](#examples--smoddit-)
* [Creating a Modifiable Contract](#creating-a-modifiable-contract)
* [Modifying a `uint256`](#modifying-a--uint256-)
* [Modifying a Struct](#modifying-a-struct)
* [Modifying a Mapping](#modifying-a-mapping)
* [Modifying a Nested Mapping](#modifying-a-nested-mapping)
## API ## API
### Functions ### Functions
#### `smockit` #### `smockit`
...@@ -122,10 +88,13 @@ const smoddit = async ( ...@@ -122,10 +88,13 @@ const smoddit = async (
#### `smockit` #### `smockit`
##### `MockContract` ##### `MockContract`
```typescript ```typescript
interface MockContract extends Contract { interface MockContract extends ethers.Contract {
smocked: { smocked: {
[functionName: string]: MockContractFunction [functionName: string]: MockContractFunction
} }
// A wallet you can use to send transactions *from* a smocked contract
wallet: ethers.Signer
} }
``` ```
...@@ -159,14 +128,14 @@ export type MockReturnValue = ...@@ -159,14 +128,14 @@ export type MockReturnValue =
#### `smoddit` #### `smoddit`
##### `ModifiableContractFactory` ##### `ModifiableContractFactory`
```typescript ```typescript
interface ModifiableContractFactory extends ContractFactory { interface ModifiableContractFactory extends ethers.ContractFactory {
deploy: (...args: any[]) => Promise<ModifiableContract> deploy: (...args: any[]) => Promise<ModifiableContract>
} }
``` ```
##### `ModifiableContract` ##### `ModifiableContract`
```typescript ```typescript
interface ModifiableContract extends Contract { interface ModifiableContract extends ethers.Contract {
smodify: { smodify: {
put: (storage: any) => Promise<void> put: (storage: any) => Promise<void>
} }
...@@ -339,6 +308,20 @@ MyMockContract.smocked.myFunction.will.revert.with('0x1234') ...@@ -339,6 +308,20 @@ MyMockContract.smocked.myFunction.will.revert.with('0x1234')
console.log(await MyMockContract.myFunction('Some return value!')) // Revert! console.log(await MyMockContract.myFunction('Some return value!')) // Revert!
``` ```
### Sending transactions from a smocked contract
```typescript
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
```
## Examples (smoddit) ## Examples (smoddit)
### Creating a Modifiable Contract ### Creating a Modifiable Contract
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
"clean": "rimraf ./artifacts ./cache ./dist ./tsconfig.build.tsbuildinfo" "clean": "rimraf ./artifacts ./cache ./dist ./tsconfig.build.tsbuildinfo"
}, },
"peerDependencies": { "peerDependencies": {
"@ethersproject/abi": "^5",
"@ethersproject/abstract-provider": "^5",
"@ethersproject/abstract-signer": "^5",
"@nomiclabs/ethereumjs-vm": "^4", "@nomiclabs/ethereumjs-vm": "^4",
"@nomiclabs/hardhat-ethers": "^2", "@nomiclabs/hardhat-ethers": "^2",
"ethers": "^5", "ethers": "^5",
...@@ -24,11 +27,12 @@ ...@@ -24,11 +27,12 @@
}, },
"dependencies": { "dependencies": {
"@eth-optimism/core-utils": "^0.4.1", "@eth-optimism/core-utils": "^0.4.1",
"@ethersproject/abi": "^5.0.13",
"@ethersproject/abstract-provider": "^5.0.10",
"bn.js": "^5.2.0" "bn.js": "^5.2.0"
}, },
"devDependencies": { "devDependencies": {
"@ethersproject/abi": "^5.1.2",
"@ethersproject/abstract-provider": "^5.1.0",
"@ethersproject/abstract-signer": "^5.1.0",
"@nomiclabs/ethereumjs-vm": "^4.2.2", "@nomiclabs/ethereumjs-vm": "^4.2.2",
"@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1", "@nomiclabs/hardhat-waffle": "^2.0.1",
......
...@@ -162,6 +162,17 @@ export const smockit = async ( ...@@ -162,6 +162,17 @@ export const smockit = async (
opts.provider || (hre as any).ethers.provider // TODO: Probably check that this exists. opts.provider || (hre as any).ethers.provider // TODO: Probably check that this exists.
) as MockContract ) as MockContract
// We attach a wallet to the contract so that users can send transactions *from* a smock.
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [contract.address]
})
// Now we actually get the signer and attach it to the mock.
contract.wallet = await (hre as any).ethers.getSigner(
contract.address
)
// Start by smocking the fallback. // Start by smocking the fallback.
contract.smocked = { contract.smocked = {
fallback: smockifyFunction( fallback: smockifyFunction(
......
/* Imports: External */ /* Imports: External */
import { Artifact } from 'hardhat/types' import { Artifact } from 'hardhat/types'
import { Contract, ContractFactory, ethers } from 'ethers' import { Contract, ContractFactory, ethers } from 'ethers'
import { Signer } from '@ethersproject/abstract-signer'
import { Provider } from '@ethersproject/abstract-provider' import { Provider } from '@ethersproject/abstract-provider'
import { JsonFragment, Fragment } from '@ethersproject/abi' import { JsonFragment, Fragment } from '@ethersproject/abi'
...@@ -47,6 +48,8 @@ export type MockContract = Contract & { ...@@ -47,6 +48,8 @@ export type MockContract = Contract & {
smocked: { smocked: {
[name: string]: MockContractFunction [name: string]: MockContractFunction
} }
wallet: Signer
} }
export interface SmockedVM { export interface SmockedVM {
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
contract TestHelpers_SenderAssertions {
function getSender()
public
view
returns (
address
)
{
return msg.sender;
}
}
/* Imports: External */
import hre from 'hardhat'
import { expect } from 'chai'
import { Contract } from 'ethers'
/* Imports: Internal */
import { smockit } from '../../src'
describe('[smock]: sending transactions from smock contracts', () => {
const ethers = (hre as any).ethers
let TestHelpers_SenderAssertions: Contract
before(async () => {
TestHelpers_SenderAssertions = await(
await ethers.getContractFactory(
'TestHelpers_SenderAssertions'
)
).deploy()
})
it('should attach a signer for a mock with a random address', async () => {
const mock = await smockit('TestHelpers_BasicReturnContract')
expect(
await TestHelpers_SenderAssertions.connect(mock.wallet).getSender()
).to.equal(mock.address)
})
it('should attach a signer for a mock with a fixed address', async () => {
const mock = await smockit('TestHelpers_BasicReturnContract', {
address: '0x1234123412341234123412341234123412341234'
})
expect(
await TestHelpers_SenderAssertions.connect(mock.wallet).getSender()
).to.equal(mock.address)
})
})
...@@ -992,7 +992,7 @@ ...@@ -992,7 +992,7 @@
"@ethersproject/properties" "^5.0.3" "@ethersproject/properties" "^5.0.3"
"@ethersproject/strings" "^5.0.4" "@ethersproject/strings" "^5.0.4"
"@ethersproject/abi@5.1.0", "@ethersproject/abi@^5.0.0", "@ethersproject/abi@^5.0.1", "@ethersproject/abi@^5.0.13", "@ethersproject/abi@^5.0.2", "@ethersproject/abi@^5.1.0": "@ethersproject/abi@5.1.0", "@ethersproject/abi@^5.0.0", "@ethersproject/abi@^5.0.1", "@ethersproject/abi@^5.0.2", "@ethersproject/abi@^5.1.0":
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.1.0.tgz#d582c9f6a8e8192778b5f2c991ce19d7b336b0c5" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.1.0.tgz#d582c9f6a8e8192778b5f2c991ce19d7b336b0c5"
integrity sha512-N/W9Sbn1/C6Kh2kuHRjf/hX6euMK4+9zdJRBB8sDWmihVntjUAfxbusGZKzDQD8i3szAHhTz8K7XADV5iFNfJw== integrity sha512-N/W9Sbn1/C6Kh2kuHRjf/hX6euMK4+9zdJRBB8sDWmihVntjUAfxbusGZKzDQD8i3szAHhTz8K7XADV5iFNfJw==
...@@ -1007,7 +1007,7 @@ ...@@ -1007,7 +1007,7 @@
"@ethersproject/properties" "^5.1.0" "@ethersproject/properties" "^5.1.0"
"@ethersproject/strings" "^5.1.0" "@ethersproject/strings" "^5.1.0"
"@ethersproject/abi@^5.0.0-beta.146": "@ethersproject/abi@5.1.2", "@ethersproject/abi@^5.0.0-beta.146", "@ethersproject/abi@^5.1.2":
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.1.2.tgz#a8e75cd0455e6dc9e4861c3d1c22bbe436c1d775" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.1.2.tgz#a8e75cd0455e6dc9e4861c3d1c22bbe436c1d775"
integrity sha512-uMhoQVPX0UtfzTpekYQSEUcJGDgsJ25ifz+SV6PDETWaUFhcR8RNgb1QPTASP13inW8r6iy0/Xdq9D5hK2pNvA== integrity sha512-uMhoQVPX0UtfzTpekYQSEUcJGDgsJ25ifz+SV6PDETWaUFhcR8RNgb1QPTASP13inW8r6iy0/Xdq9D5hK2pNvA==
...@@ -1022,7 +1022,7 @@ ...@@ -1022,7 +1022,7 @@
"@ethersproject/properties" "^5.1.0" "@ethersproject/properties" "^5.1.0"
"@ethersproject/strings" "^5.1.0" "@ethersproject/strings" "^5.1.0"
"@ethersproject/abstract-provider@5.1.0", "@ethersproject/abstract-provider@^5.0.0", "@ethersproject/abstract-provider@^5.0.10", "@ethersproject/abstract-provider@^5.0.5", "@ethersproject/abstract-provider@^5.0.8", "@ethersproject/abstract-provider@^5.0.9", "@ethersproject/abstract-provider@^5.1.0": "@ethersproject/abstract-provider@5.1.0", "@ethersproject/abstract-provider@^5.0.0", "@ethersproject/abstract-provider@^5.0.5", "@ethersproject/abstract-provider@^5.0.8", "@ethersproject/abstract-provider@^5.0.9", "@ethersproject/abstract-provider@^5.1.0":
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.1.0.tgz#1f24c56cda5524ef4ed3cfc562a01d6b6f8eeb0b" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.1.0.tgz#1f24c56cda5524ef4ed3cfc562a01d6b6f8eeb0b"
integrity sha512-8dJUnT8VNvPwWhYIau4dwp7qe1g+KgdRm4XTWvjkI9gAT2zZa90WF5ApdZ3vl1r6NDmnn6vUVvyphClRZRteTQ== integrity sha512-8dJUnT8VNvPwWhYIau4dwp7qe1g+KgdRm4XTWvjkI9gAT2zZa90WF5ApdZ3vl1r6NDmnn6vUVvyphClRZRteTQ==
...@@ -1314,6 +1314,21 @@ ...@@ -1314,6 +1314,21 @@
"@ethersproject/rlp" "^5.1.0" "@ethersproject/rlp" "^5.1.0"
"@ethersproject/signing-key" "^5.1.0" "@ethersproject/signing-key" "^5.1.0"
"@ethersproject/transactions@5.1.1", "@ethersproject/transactions@^5.0.21":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.1.1.tgz#5a6bbb25fb062c3cc75eb0db12faefcdd3870813"
integrity sha512-Nwgbp09ttIVN0OoUBatCXaHxR7grWPHbozJN8v7AXDLrl6nnOIBEMDh+yJTnosSQlFhcyjfTGGN+Mx6R8HdvMw==
dependencies:
"@ethersproject/address" "^5.1.0"
"@ethersproject/bignumber" "^5.1.0"
"@ethersproject/bytes" "^5.1.0"
"@ethersproject/constants" "^5.1.0"
"@ethersproject/keccak256" "^5.1.0"
"@ethersproject/logger" "^5.1.0"
"@ethersproject/properties" "^5.1.0"
"@ethersproject/rlp" "^5.1.0"
"@ethersproject/signing-key" "^5.1.0"
"@ethersproject/units@5.1.0", "@ethersproject/units@^5.0.0": "@ethersproject/units@5.1.0", "@ethersproject/units@^5.0.0":
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.1.0.tgz#b6ab3430ebc22adc3cb4839516496f167bee3ad5" resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.1.0.tgz#b6ab3430ebc22adc3cb4839516496f167bee3ad5"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment