Skip to content

Commit

Permalink
chore: version 2.1.0 (#128)
Browse files Browse the repository at this point in the history
* feat: add setVariables function (#112)

Adding a new function for mock contracts. With setVariables mocks will
be able to edit multiple internal variables at once.

* feat: ignore gas param in abi (#123)

* feat: ignore gas param in abi

* feat: lint json

* feat: add pre commit linter (#122)

* feat: setup pre-commit linter

* feat: remove test contracts from lint input

* feat: tag specific version for lint-staged

* feat: trigger linter check on pull request

* feat: set husky pre-commit hook to be executable

* feat: add support for large bytes > 31 bytes (#124)

* feat: add type definition (#126)

* chore: multiple compiler support in hardhat config (#127)

* chore(release): 2.1.0

Co-authored-by: Antonios Kogias <[email protected]>
Co-authored-by: 5h4z4mm <[email protected]>
Co-authored-by: Eugenio <[email protected]>
Co-authored-by: 0xGorilla <[email protected]>
  • Loading branch information
5 people authored Jun 24, 2022
1 parent 27fe7a5 commit f09ddab
Show file tree
Hide file tree
Showing 16 changed files with 662 additions and 126 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Lint

on: [push]
on: [pull_request, push]

jobs:
files:
Expand Down
Empty file modified .husky/commit-msg
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion .husky/pre-commit
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run lint:fix
npx lint-staged
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"extends": "solhint:recommended",
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error",
"prettier/prettier": "warn",
"compiler-version": ["off"],
"constructor-syntax": "warn",
"quotes": ["error", "single"],
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [2.1.0](https://github.com/defi-wonderland/smock/compare/v2.0.7...v2.1.0) (2022-06-24)


### Features

* add pre commit linter ([#122](https://github.com/defi-wonderland/smock/issues/122)) ([645bf79](https://github.com/defi-wonderland/smock/commit/645bf7919cbc8d592655c1a92ea32479f9d93ef6))
* add setVariables function ([#112](https://github.com/defi-wonderland/smock/issues/112)) ([72aec14](https://github.com/defi-wonderland/smock/commit/72aec1427de6f4c29cce297d75202c75e209c43e))
* add support for large bytes > 31 bytes ([#124](https://github.com/defi-wonderland/smock/issues/124)) ([9cc9a77](https://github.com/defi-wonderland/smock/commit/9cc9a773496bd389b61f720a4c5c7f3c2efc99df))
* add type definition ([#126](https://github.com/defi-wonderland/smock/issues/126)) ([e38fb3a](https://github.com/defi-wonderland/smock/commit/e38fb3a07422c095de8b59596ac90c577254cc59))
* added wallet to mocks ([#96](https://github.com/defi-wonderland/smock/issues/96)) ([22c4278](https://github.com/defi-wonderland/smock/commit/22c4278c1c4fb6627c2e444b341749f93be4b244))
* ignore gas param in abi ([#123](https://github.com/defi-wonderland/smock/issues/123)) ([71ac4fc](https://github.com/defi-wonderland/smock/commit/71ac4fc204681f284df3a4a8d2633c9240778a68))


### Bug Fixes

* returns working with struct mappings ([#103](https://github.com/defi-wonderland/smock/issues/103)) ([27fe7a5](https://github.com/defi-wonderland/smock/commit/27fe7a5f3c351714257cdc98204e282932c11e12)), closes [#94](https://github.com/defi-wonderland/smock/issues/94)

### [2.0.7](https://github.com/defi-wonderland/smock/compare/v2.0.2...v2.0.7) (2021-09-30)


Expand Down
26 changes: 16 additions & 10 deletions docs/source/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,16 @@ If you'd like to use mocks, you **must** update your :code:`hardhat.config.<js/t
... // your other hardhat settings go here
solidity: {
... // your other Solidity settings go here
settings: {
outputSelection: {
"*": {
"*": ["storageLayout"]
compilers: [
...// compiler options
settings: {
outputSelection: {
"*": {
"*": ["storageLayout"]
}
}
}
}
]
}
}
Expand All @@ -61,13 +64,16 @@ If you'd like to use mocks, you **must** update your :code:`hardhat.config.<js/t
... // your other hardhat settings go here
solidity: {
... // your other Solidity settings go here
settings: {
outputSelection: {
"*": {
"*": ["storageLayout"]
compilers: [
...// compiler options
settings: {
outputSelection: {
"*": {
"*": ["storageLayout"]
}
}
}
}
]
}
}
Expand Down
20 changes: 19 additions & 1 deletion docs/source/mocks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,22 @@ Setting the value of a nested mapping
myChildMapping: {
myKey: 1234
}
});
});
Setting the value of multiple variables
#######################################

.. code-block:: typescript
await myMock.setVariables({
myVariableName1: 123,
myVariableName2: true,
myStruct: {
valueA: 1234,
valueB: false,
},
myMapping: {
[myKey]: 1234
}
})
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@defi-wonderland/smock",
"version": "2.0.7",
"version": "2.1.0",
"description": "The Solidity mocking library",
"keywords": [
"ethereum",
Expand Down Expand Up @@ -40,11 +40,17 @@
"lint:check": "cross-env solhint 'contracts/**/*.sol' 'interfaces/**/*.sol' && cross-env prettier --check './**'",
"lint:fix": "sort-package-json && cross-env prettier --write './**' && cross-env solhint --fix 'contracts/**/*.sol' 'interfaces/**/*.sol'",
"docs:md": "pandoc README.rst -f rst -t markdown -o README.md",
"prepare": "husky install",
"release": "yarn build && yarn docs:md && standard-version",
"pre-release": "yarn build && standard-version --prerelease rc",
"docs:install": "pip install -r docs/requirements.txt",
"docs:watch": "sphinx-autobuild -a docs/source docs/_build/html --watch docs/source --watch README.rst"
},
"lint-staged": {
"*.{js,css,md,ts}": "prettier --write",
"*.sol": "cross-env solhint --fix 'contracts/**/*.sol' 'interfaces/**/*.sol'",
"package.json": "sort-package-json"
},
"resolutions": {
"@ethereumjs/block": "3.2.1",
"@ethereumjs/blockchain": "5.2.1",
Expand Down Expand Up @@ -83,6 +89,7 @@
"hardhat-preprocessor": "0.1.4",
"husky": "6.0.0",
"inquirer": "8.1.0",
"lint-staged": "12.5.0",
"mocha": "9.0.0",
"pinst": "2.1.6",
"prettier": "2.3.1",
Expand Down
1 change: 1 addition & 0 deletions src/factories/smock-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function mockifyContractFactory<T extends ContractFactory>(
// attach to every internal variable, all the editable logic
const editableStorage = new EditableStorage(await getStorageLayout(contractName), vm.getManager(), mock.address);
mock.setVariable = editableStorage.setVariable.bind(editableStorage);
mock.setVariables = editableStorage.setVariables.bind(editableStorage);

// We attach a wallet to the contract so that users can send transactions *from* a watchablecontract.
mock.wallet = await impersonate(mock.address);
Expand Down
16 changes: 12 additions & 4 deletions src/logic/editable-storage-logic.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { SmockVMManager } from '../types';
import { SetVariablesType, SmockVMManager } from '../types';
import { fromHexString, toFancyAddress } from '../utils';
import { computeStorageSlots } from '../utils/storage';
import { computeStorageSlots, SolidityStorageLayout } from '../utils/storage';

export class EditableStorageLogic {
private storageLayout: any;
private storageLayout: SolidityStorageLayout;
private contractAddress: string;
private vmManager: SmockVMManager;

constructor(storageLayout: any, vmManager: SmockVMManager, contractAddress: string) {
constructor(storageLayout: SolidityStorageLayout, vmManager: SmockVMManager, contractAddress: string) {
this.storageLayout = storageLayout;
this.vmManager = vmManager;
this.contractAddress = contractAddress;
Expand All @@ -22,4 +22,12 @@ export class EditableStorageLogic {
await this.vmManager.putContractStorage(toFancyAddress(this.contractAddress), fromHexString(slot.key), fromHexString(slot.val));
}
}

async setVariables(variables: SetVariablesType) {
if (variables === undefined || variables === null) return;

for (const [variableName, variableValue] of Object.entries(variables)) {
await this.setVariable(variableName, variableValue);
}
}
}
9 changes: 8 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { BaseContract, ContractFactory, ethers } from 'ethers';
import { EditableStorageLogic } from './logic/editable-storage-logic';
import { WatchableFunctionLogic } from './logic/watchable-function-logic';

type Abi = ReadonlyArray<Fragment | JsonFragment | string>;
type Abi = ReadonlyArray<
Fragment | Pick<JsonFragment, 'name' | 'type' | 'anonymous' | 'payable' | 'constant' | 'stateMutability' | 'inputs' | 'outputs'> | string
>;
export type FakeContractSpec = { abi?: Abi; interface?: Interface } | Abi | ethers.utils.Interface | string;

export interface FakeContractOptions {
Expand Down Expand Up @@ -34,6 +36,10 @@ export interface ContractCall {
target: string;
}

export interface SetVariablesType {
[variablesName: string]: any;
}

export type WhenCalledWithChain = {
returns: (value?: ProgrammedReturnValue) => void;
reverts: (reason?: string) => void;
Expand Down Expand Up @@ -64,6 +70,7 @@ export type FakeContract<T extends BaseContract = BaseContract> = SmockContractB
export type MockContract<T extends BaseContract = BaseContract> = SmockContractBase<T> & {
connect: (...args: Parameters<T['connect']>) => MockContract<T>;
setVariable: EditableStorageLogic['setVariable'];
setVariables: EditableStorageLogic['setVariables'];
} & {
[Property in keyof T['functions']]: ProgrammableContractFunction;
};
Expand Down
26 changes: 22 additions & 4 deletions src/utils/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,28 @@ function encodeVariable(
},
];
} else {
// TODO: add support for large strings or byte arrays
throw new Error(
'large strings (> 31 bytes) not supported. Follow this issue for more info: https://github.com/defi-wonderland/smock/issues/30'
);
let slots: StorageSlotPair[] = [];
// According to the solidity docs (https://docs.soliditylang.org/en/v0.8.4/internals/layout_in_storage.html#bytes-and-string)
// For bytes or strings that store data which is 32 or more bytes long, the main slot p stores length * 2 + 1
// and the data is stored as usual in keccak256(p)
slots = slots.concat({
key: slotKey,
val: padNumHexSlotValue(bytes.length * 2 + 1, 0),
});

// Each storage slot has 32 bytes so we make sure to slice the large bytes into 32bytes chunks
for (let i = 0; i * 32 < bytes.length; i++) {
// We calculate the Storage Slot key based on the solidity docs (see above link)
let key = BigNumber.from(ethers.utils.keccak256(slotKey))
.add(BigNumber.from(i.toString(16)))
.toHexString();
slots = slots.concat({
key: key,
val: ethers.utils.hexlify(ethers.utils.concat([bytes.slice(i * 32, i * 32 + 32), ethers.constants.HashZero]).slice(0, 32)),
});
}

return slots;
}
} else if (variableType.encoding === 'mapping') {
if (variableType.key === undefined || variableType.value === undefined) {
Expand Down
6 changes: 6 additions & 0 deletions test/unit/fake/initialization.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Receiver, Receiver__factory, Returner } from '@typechained';
import receiverArtifact from 'artifacts/test/contracts/watchable-function-logic/Receiver.sol/Receiver.json';
import chai, { expect } from 'chai';
import { ethers, network } from 'hardhat';
import storageArtifact from 'test/unit/fake/testdata/Storage.json';

chai.use(smock.matchers);

Expand Down Expand Up @@ -84,4 +85,9 @@ describe('Fake: Initialization', () => {
const fake = await smock.fake('Receiver');
expect(fake.wallet._isSigner).to.be.true;
});

it('should work for abi with gas parameter', async () => {
const fake = await smock.fake(storageArtifact);
expect(fake.store._watchable).not.to.be.undefined;
});
});
29 changes: 29 additions & 0 deletions test/unit/fake/testdata/Storage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[
{
"inputs": [],
"name": "retrieve",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "store",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function",
"gas": 12345
}
]
Loading

0 comments on commit f09ddab

Please sign in to comment.