@1inch/solidity-utils 1.2.8 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +7 -0
- package/README.md +1 -1
- package/contracts/GasChecker.sol +1 -1
- package/contracts/libraries/AddressArray.sol +13 -3
- package/contracts/libraries/RevertReasonParser.sol +1 -1
- package/contracts/libraries/StringUtil.sol +2 -2
- package/contracts/libraries/UniERC20.sol +1 -1
- package/dist/src/asserts.d.ts +3 -0
- package/dist/src/asserts.js +28 -0
- package/dist/src/asserts.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +10 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/permit.d.ts +79 -0
- package/dist/src/permit.js +98 -0
- package/dist/src/permit.js.map +1 -0
- package/dist/src/prelude.d.ts +20 -0
- package/dist/src/prelude.js +32 -0
- package/dist/src/prelude.js.map +1 -0
- package/dist/src/profileEVM.d.ts +9 -0
- package/{js → dist/src}/profileEVM.js +42 -57
- package/dist/src/profileEVM.js.map +1 -0
- package/dist/src/utils.d.ts +14 -0
- package/dist/src/utils.js +58 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +67 -40
- package/contracts/mocks/DaiLikePermitMock.sol +0 -44
- package/js/asserts.js +0 -34
- package/js/permit.js +0 -110
- package/js/utils.js +0 -68
- package/utils/contract.hbs +0 -69
- package/utils/docify.utils.js +0 -127
- package/utils/solidity-docgen-helpers.js +0 -24
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.countInstructions = exports.signMessage = exports.fixSignature = exports.trackReceivedTokenAndTx = exports.timeIncreaseTo = void 0;
|
|
4
|
+
const util_1 = require("util");
|
|
5
|
+
const prelude_1 = require("./prelude");
|
|
6
|
+
async function timeIncreaseTo(seconds) {
|
|
7
|
+
const delay = 1000 - new Date().getMilliseconds();
|
|
8
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
9
|
+
await prelude_1.time.increaseTo(seconds);
|
|
10
|
+
}
|
|
11
|
+
exports.timeIncreaseTo = timeIncreaseTo;
|
|
12
|
+
async function trackReceivedTokenAndTx(token, wallet, txPromise, ...args) {
|
|
13
|
+
const [balanceFunc, isETH] = 'balanceOf' in token
|
|
14
|
+
? [() => token.balanceOf(wallet), false]
|
|
15
|
+
: [async () => (0, prelude_1.toBN)(await web3.eth.getBalance(wallet)), true];
|
|
16
|
+
const preBalance = await balanceFunc();
|
|
17
|
+
const txResult = await txPromise(...args);
|
|
18
|
+
const txFees = (wallet.toLowerCase() === txResult.receipt.from.toLowerCase() && isETH)
|
|
19
|
+
? (0, prelude_1.toBN)(txResult.receipt.gasUsed).mul((0, prelude_1.toBN)(txResult.receipt.effectiveGasPrice))
|
|
20
|
+
: (0, prelude_1.toBN)('0');
|
|
21
|
+
const postBalance = await balanceFunc();
|
|
22
|
+
return [postBalance.sub(preBalance).add(txFees), txResult];
|
|
23
|
+
}
|
|
24
|
+
exports.trackReceivedTokenAndTx = trackReceivedTokenAndTx;
|
|
25
|
+
function fixSignature(signature) {
|
|
26
|
+
// in geth its always 27/28, in ganache its 0/1. Change to 27/28 to prevent
|
|
27
|
+
// signature malleability if version is 0/1
|
|
28
|
+
// see https://github.com/ethereum/go-ethereum/blob/v1.8.23/internal/ethapi/api.go#L465
|
|
29
|
+
let v = parseInt(signature.slice(130, 132), 16);
|
|
30
|
+
if (v < 27) {
|
|
31
|
+
v += 27;
|
|
32
|
+
}
|
|
33
|
+
const vHex = v.toString(16);
|
|
34
|
+
return signature.slice(0, 130) + vHex;
|
|
35
|
+
}
|
|
36
|
+
exports.fixSignature = fixSignature;
|
|
37
|
+
// signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
|
|
38
|
+
async function signMessage(signer, messageHex = '0x') {
|
|
39
|
+
return fixSignature(await web3.eth.sign(messageHex, signer));
|
|
40
|
+
}
|
|
41
|
+
exports.signMessage = signMessage;
|
|
42
|
+
async function countInstructions(txHash, instructions) {
|
|
43
|
+
if (!web3.currentProvider || typeof web3.currentProvider === 'string' || !web3.currentProvider.send) {
|
|
44
|
+
throw new Error('Unsupported provider');
|
|
45
|
+
}
|
|
46
|
+
const trace = await (0, util_1.promisify)(web3.currentProvider.send.bind(web3.currentProvider))({
|
|
47
|
+
jsonrpc: '2.0',
|
|
48
|
+
method: 'debug_traceTransaction',
|
|
49
|
+
params: [txHash, {}],
|
|
50
|
+
id: new Date().getTime(),
|
|
51
|
+
});
|
|
52
|
+
const str = JSON.stringify(trace);
|
|
53
|
+
return instructions.map(instr => {
|
|
54
|
+
return str.split('"' + instr.toUpperCase() + '"').length - 1;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
exports.countInstructions = countInstructions;
|
|
58
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,60 +1,87 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1inch/solidity-utils",
|
|
3
|
-
"version": "
|
|
4
|
-
"main": "index.js",
|
|
3
|
+
"version": "2.0.4",
|
|
4
|
+
"main": "dist/src/index.js",
|
|
5
|
+
"types": "dist/src/index.d.ts",
|
|
5
6
|
"repository": {
|
|
6
7
|
"type": "git",
|
|
7
8
|
"url": "git+ssh://git@github.com/1inch/solidity-utils.git"
|
|
8
9
|
},
|
|
9
10
|
"license": "MIT",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"prebuild": "rimraf ./dist && cti src -b",
|
|
13
|
+
"build": "tsc -p tsconfig.publish.json",
|
|
14
|
+
"postbuild": "echo done",
|
|
15
|
+
"publishPackage": "yarn build && yarn publish",
|
|
16
|
+
"coverage": "hardhat coverage",
|
|
17
|
+
"lint": "yarn run lint:ts && yarn run lint:sol",
|
|
18
|
+
"lint:fix": "yarn run lint:ts:fix && yarn run lint:sol:fix",
|
|
19
|
+
"lint:ts": "eslint . --ext .ts",
|
|
20
|
+
"lint:ts:fix": "eslint . --fix --ext .ts",
|
|
21
|
+
"lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"",
|
|
22
|
+
"lint:sol:fix": "solhint --max-warnings 0 \"contracts/**/*.sol\" --fix",
|
|
23
|
+
"test": "hardhat test",
|
|
24
|
+
"typecheck": "tsc --noEmit --skipLibCheck",
|
|
25
|
+
"typechain": "hardhat typechain"
|
|
26
|
+
},
|
|
10
27
|
"dependencies": {
|
|
11
|
-
"@
|
|
12
|
-
"
|
|
28
|
+
"@metamask/eth-sig-util": "^4.0.0",
|
|
29
|
+
"@openzeppelin/contracts": "4.5.0",
|
|
30
|
+
"@openzeppelin/test-helpers": "0.5.15",
|
|
31
|
+
"chai": "4.3.6",
|
|
32
|
+
"chai-as-promised": "7.1.1",
|
|
33
|
+
"ethereumjs-wallet": "1.0.2",
|
|
34
|
+
"hardhat": "2.8.4",
|
|
35
|
+
"web3-utils": "1.7.0"
|
|
13
36
|
},
|
|
14
37
|
"devDependencies": {
|
|
15
|
-
"@nomiclabs/hardhat-etherscan": "
|
|
16
|
-
"@nomiclabs/hardhat-truffle5": "
|
|
17
|
-
"@nomiclabs/hardhat-web3": "
|
|
18
|
-
"@
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"eslint-plugin
|
|
25
|
-
"eslint
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
38
|
+
"@nomiclabs/hardhat-etherscan": "3.0.1",
|
|
39
|
+
"@nomiclabs/hardhat-truffle5": "2.0.4",
|
|
40
|
+
"@nomiclabs/hardhat-web3": "2.0.0",
|
|
41
|
+
"@typechain/hardhat": "4.0.0",
|
|
42
|
+
"@typechain/truffle-v5": "7.0.0",
|
|
43
|
+
"@types/chai": "4.3.0",
|
|
44
|
+
"@types/chai-as-promised": "7.1.5",
|
|
45
|
+
"@types/mocha": "9.1.0",
|
|
46
|
+
"@types/node": "17.0.18",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "5.12.0",
|
|
48
|
+
"@typescript-eslint/parser": "5.12.0",
|
|
49
|
+
"chai-bn": "0.3.1",
|
|
50
|
+
"create-ts-index": "^1.14.0",
|
|
51
|
+
"cross-spawn": "7.0.3",
|
|
52
|
+
"dotenv": "16.0.0",
|
|
53
|
+
"eslint": "8.9.0",
|
|
54
|
+
"eslint-config-standard": "16.0.3",
|
|
55
|
+
"eslint-plugin-import": "2.25.4",
|
|
56
|
+
"eslint-plugin-node": "11.1.0",
|
|
57
|
+
"eslint-plugin-promise": "6.0.0",
|
|
58
|
+
"eslint-plugin-standard": "5.0.0",
|
|
59
|
+
"eslint-plugin-typescript": "0.14.0",
|
|
60
|
+
"hardhat-deploy": "0.10.5",
|
|
61
|
+
"hardhat-gas-reporter": "1.0.8",
|
|
62
|
+
"rimraf": "3.0.2",
|
|
63
|
+
"shx": "0.3.4",
|
|
64
|
+
"solc": "0.8.11",
|
|
65
|
+
"solhint": "3.3.7",
|
|
66
|
+
"solidity-coverage": "0.7.20",
|
|
67
|
+
"ts-node": "10.5.0",
|
|
68
|
+
"typechain": "7.0.0",
|
|
69
|
+
"typescript": "4.5.5"
|
|
36
70
|
},
|
|
37
71
|
"bin": {
|
|
38
72
|
"solidity-utils-docify": "utils/docify.utils.js"
|
|
39
73
|
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "rimraf ./dist && mkdir dist && shx cp -R js ./dist/js && shx cp -R utils ./dist/utils && shx cp package.json ./dist && shx cp README.md ./dist && shx cp -R ./contracts ./dist/contracts && shx rm -rf dist/contracts/mocks dist/contracts/tests && shx mkdir -p dist/contracts/mocks && shx cp ./contracts/mocks/DaiLikePermitMock.sol dist/contracts/mocks/",
|
|
42
|
-
"coverage": "hardhat coverage",
|
|
43
|
-
"lint": "yarn run lint:js && yarn run lint:sol",
|
|
44
|
-
"lint:fix": "yarn run lint:js:fix && yarn run lint:sol:fix",
|
|
45
|
-
"lint:js": "eslint .",
|
|
46
|
-
"lint:js:fix": "eslint . --fix",
|
|
47
|
-
"lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"",
|
|
48
|
-
"lint:sol:fix": "solhint --max-warnings 0 \"contracts/**/*.sol\" --fix",
|
|
49
|
-
"test": "hardhat test"
|
|
50
|
-
},
|
|
51
74
|
"bugs": {
|
|
52
75
|
"url": "https://github.com/1inch/solidity-utils/issues"
|
|
53
76
|
},
|
|
54
77
|
"homepage": "https://github.com/1inch/solidity-utils#readme",
|
|
55
|
-
"directories": {
|
|
56
|
-
"test": "test"
|
|
57
|
-
},
|
|
58
78
|
"author": "1inch",
|
|
59
|
-
"description": "Solidity and
|
|
79
|
+
"description": "Solidity and TS utils",
|
|
80
|
+
"files": [
|
|
81
|
+
"./dist",
|
|
82
|
+
"./*.MD",
|
|
83
|
+
"contracts/*.sol",
|
|
84
|
+
"contracts/interfaces",
|
|
85
|
+
"contracts/libraries"
|
|
86
|
+
]
|
|
60
87
|
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
|
|
3
|
-
pragma solidity ^0.8.0;
|
|
4
|
-
|
|
5
|
-
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
|
|
6
|
-
|
|
7
|
-
contract DaiLikePermitMock is ERC20Permit {
|
|
8
|
-
// bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
|
|
9
|
-
bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
string memory name,
|
|
13
|
-
string memory symbol,
|
|
14
|
-
address initialAccount,
|
|
15
|
-
uint256 initialBalance
|
|
16
|
-
) payable ERC20(name, symbol) ERC20Permit(name) {
|
|
17
|
-
_mint(initialAccount, initialBalance);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external
|
|
21
|
-
{
|
|
22
|
-
bytes32 digest =
|
|
23
|
-
keccak256(abi.encodePacked(
|
|
24
|
-
"\x19\x01",
|
|
25
|
-
this.DOMAIN_SEPARATOR(),
|
|
26
|
-
keccak256(abi.encode(PERMIT_TYPEHASH,
|
|
27
|
-
holder,
|
|
28
|
-
spender,
|
|
29
|
-
nonce,
|
|
30
|
-
expiry,
|
|
31
|
-
allowed))
|
|
32
|
-
));
|
|
33
|
-
|
|
34
|
-
require(holder != address(0), "Dai/invalid-address-0");
|
|
35
|
-
require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");
|
|
36
|
-
// solhint-disable-next-line not-rely-on-time
|
|
37
|
-
require(expiry == 0 || block.timestamp <= expiry, "Dai/permit-expired");
|
|
38
|
-
require(nonce == nonces(holder), "Dai/invalid-nonce");
|
|
39
|
-
_useNonce(holder);
|
|
40
|
-
uint wad = allowed ? type(uint128).max : 0;
|
|
41
|
-
_approve(holder, spender, wad);
|
|
42
|
-
emit Approval(holder, spender, wad);
|
|
43
|
-
}
|
|
44
|
-
}
|
package/js/asserts.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const { expect } = require('chai');
|
|
2
|
-
const { BN } = require('@openzeppelin/test-helpers');
|
|
3
|
-
|
|
4
|
-
async function assertThrowsAsync (action, msg) {
|
|
5
|
-
try {
|
|
6
|
-
await action();
|
|
7
|
-
} catch (e) {
|
|
8
|
-
expect(e.message).to.contain(msg);
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
throw new Error('Should have thrown an error but didn\'t');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function assertRoughlyEqualValues (expected, actual, relativeDiff) {
|
|
15
|
-
const expectedBN = new BN(expected);
|
|
16
|
-
const actualBN = new BN(actual);
|
|
17
|
-
|
|
18
|
-
let multiplerNumerator = relativeDiff;
|
|
19
|
-
let multiplerDenominator = new BN('1');
|
|
20
|
-
while (!Number.isInteger(multiplerNumerator)) {
|
|
21
|
-
multiplerDenominator = multiplerDenominator.mul(new BN('10'));
|
|
22
|
-
multiplerNumerator *= 10;
|
|
23
|
-
}
|
|
24
|
-
const diff = expectedBN.sub(actualBN).abs();
|
|
25
|
-
const treshold = expectedBN.mul(new BN(multiplerNumerator.toString())).div(multiplerDenominator);
|
|
26
|
-
if (!diff.lte(treshold)) {
|
|
27
|
-
expect(actualBN).to.be.bignumber.equal(expectedBN, `${actualBN} != ${expectedBN} with ${relativeDiff} precision`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
module.exports = {
|
|
32
|
-
assertThrowsAsync,
|
|
33
|
-
assertRoughlyEqualValues,
|
|
34
|
-
};
|
package/js/permit.js
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
const { constants } = require('@openzeppelin/test-helpers');
|
|
2
|
-
const ethSigUtil = require('eth-sig-util');
|
|
3
|
-
const { fromRpcSig } = require('ethereumjs-util');
|
|
4
|
-
const { artifacts } = require('hardhat');
|
|
5
|
-
const ERC20Permit = artifacts.require('@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol:ERC20Permit');
|
|
6
|
-
const ERC20PermitLikeDai = artifacts.require('DaiLikePermitMock');
|
|
7
|
-
|
|
8
|
-
const defaultDeadline = constants.MAX_UINT256;
|
|
9
|
-
|
|
10
|
-
const EIP712Domain = [
|
|
11
|
-
{ name: 'name', type: 'string' },
|
|
12
|
-
{ name: 'version', type: 'string' },
|
|
13
|
-
{ name: 'chainId', type: 'uint256' },
|
|
14
|
-
{ name: 'verifyingContract', type: 'address' },
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
const Permit = [
|
|
18
|
-
{ name: 'owner', type: 'address' },
|
|
19
|
-
{ name: 'spender', type: 'address' },
|
|
20
|
-
{ name: 'value', type: 'uint256' },
|
|
21
|
-
{ name: 'nonce', type: 'uint256' },
|
|
22
|
-
{ name: 'deadline', type: 'uint256' },
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
const DaiLikePermit = [
|
|
26
|
-
{ name: 'holder', type: 'address' },
|
|
27
|
-
{ name: 'spender', type: 'address' },
|
|
28
|
-
{ name: 'nonce', type: 'uint256' },
|
|
29
|
-
{ name: 'expiry', type: 'uint256' },
|
|
30
|
-
{ name: 'allowed', type: 'bool' },
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
function trim0x (bigNumber) {
|
|
34
|
-
const s = bigNumber.toString();
|
|
35
|
-
if (s.startsWith('0x')) {
|
|
36
|
-
return s.substring(2);
|
|
37
|
-
}
|
|
38
|
-
return s;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function cutSelector (data) {
|
|
42
|
-
const hexPrefix = '0x';
|
|
43
|
-
return hexPrefix + data.substr(hexPrefix.length + 8);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function domainSeparator (name, version, chainId, verifyingContract) {
|
|
47
|
-
return '0x' + ethSigUtil.TypedDataUtils.hashStruct(
|
|
48
|
-
'EIP712Domain',
|
|
49
|
-
{ name, version, chainId, verifyingContract },
|
|
50
|
-
{ EIP712Domain },
|
|
51
|
-
).toString('hex');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function buildData (name, version, chainId, verifyingContract, owner, spender, value, nonce, deadline = defaultDeadline) {
|
|
55
|
-
return {
|
|
56
|
-
primaryType: 'Permit',
|
|
57
|
-
types: { EIP712Domain, Permit },
|
|
58
|
-
domain: { name, version, chainId, verifyingContract },
|
|
59
|
-
message: { owner, spender, value, nonce, deadline },
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function buildDataLikeDai (name, version, chainId, verifyingContract, holder, spender, nonce, allowed, expiry = defaultDeadline) {
|
|
64
|
-
return {
|
|
65
|
-
primaryType: 'Permit',
|
|
66
|
-
types: { EIP712Domain, Permit: DaiLikePermit },
|
|
67
|
-
domain: { name, version, chainId, verifyingContract },
|
|
68
|
-
message: { holder, spender, nonce, expiry, allowed },
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function getPermit (owner, ownerPrivateKey, token, tokenVersion, chainId, spender, value, deadline = defaultDeadline) {
|
|
73
|
-
const permitContract = await ERC20Permit.at(token.address);
|
|
74
|
-
const nonce = await permitContract.nonces(owner);
|
|
75
|
-
const name = await permitContract.name();
|
|
76
|
-
const data = buildData(name, tokenVersion, chainId, token.address, owner, spender, value, nonce, deadline);
|
|
77
|
-
const signature = ethSigUtil.signTypedMessage(Buffer.from(trim0x(ownerPrivateKey), 'hex'), { data });
|
|
78
|
-
const { v, r, s } = fromRpcSig(signature);
|
|
79
|
-
const permitCall = permitContract.contract.methods.permit(owner, spender, value, deadline, v, r, s).encodeABI();
|
|
80
|
-
return cutSelector(permitCall);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function getPermitLikeDai (holder, holderPrivateKey, token, tokenVersion, chainId, spender, allowed, expiry = defaultDeadline) {
|
|
84
|
-
const permitContract = await ERC20PermitLikeDai.at(token.address);
|
|
85
|
-
const nonce = await permitContract.nonces(holder);
|
|
86
|
-
const name = await permitContract.name();
|
|
87
|
-
const data = buildDataLikeDai(name, tokenVersion, chainId, token.address, holder, spender, nonce, allowed, expiry);
|
|
88
|
-
const signature = ethSigUtil.signTypedMessage(Buffer.from(trim0x(holderPrivateKey), 'hex'), { data });
|
|
89
|
-
const { v, r, s } = fromRpcSig(signature);
|
|
90
|
-
const permitCall = permitContract.contract.methods.permit(holder, spender, nonce, expiry, allowed, v, r, s).encodeABI();
|
|
91
|
-
return cutSelector(permitCall);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function withTarget (target, data) {
|
|
95
|
-
return target.toString() + trim0x(data);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
module.exports = {
|
|
99
|
-
defaultDeadline,
|
|
100
|
-
EIP712Domain,
|
|
101
|
-
Permit,
|
|
102
|
-
DaiLikePermit,
|
|
103
|
-
trim0x,
|
|
104
|
-
domainSeparator,
|
|
105
|
-
buildData,
|
|
106
|
-
buildDataLikeDai,
|
|
107
|
-
getPermit,
|
|
108
|
-
getPermitLikeDai,
|
|
109
|
-
withTarget,
|
|
110
|
-
};
|
package/js/utils.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
const { constants, time } = require('@openzeppelin/test-helpers');
|
|
2
|
-
const { promisify } = require('util');
|
|
3
|
-
|
|
4
|
-
async function timeIncreaseTo (seconds) {
|
|
5
|
-
const delay = 1000 - new Date().getMilliseconds();
|
|
6
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
7
|
-
await time.increaseTo(seconds);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
async function trackReceivedToken (token, wallet, txPromise, ...args) {
|
|
11
|
-
return (await trackReceivedTokenAndTx(token, wallet, txPromise, ...args))[0];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async function trackReceivedTokenAndTx (token, wallet, txPromise, ...args) {
|
|
15
|
-
const isETH = token.address === constants.ZERO_ADDRESS || token.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
16
|
-
const preBalance = web3.utils.toBN(isETH ? await web3.eth.getBalance(wallet) : await token.balanceOf(wallet));
|
|
17
|
-
const txResult = await txPromise(...args);
|
|
18
|
-
const txFees = (wallet.toLowerCase() === txResult.receipt.from.toLowerCase() && isETH)
|
|
19
|
-
? web3.utils.toBN(txResult.receipt.gasUsed).mul(web3.utils.toBN(txResult.receipt.effectiveGasPrice))
|
|
20
|
-
: web3.utils.toBN('0');
|
|
21
|
-
const postBalance = web3.utils.toBN(isETH ? await web3.eth.getBalance(wallet) : await token.balanceOf(wallet));
|
|
22
|
-
return [postBalance.sub(preBalance).add(txFees), txResult];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function fixSignature (signature) {
|
|
26
|
-
// in geth its always 27/28, in ganache its 0/1. Change to 27/28 to prevent
|
|
27
|
-
// signature malleability if version is 0/1
|
|
28
|
-
// see https://github.com/ethereum/go-ethereum/blob/v1.8.23/internal/ethapi/api.go#L465
|
|
29
|
-
let v = parseInt(signature.slice(130, 132), 16);
|
|
30
|
-
if (v < 27) {
|
|
31
|
-
v += 27;
|
|
32
|
-
}
|
|
33
|
-
const vHex = v.toString(16);
|
|
34
|
-
return signature.slice(0, 130) + vHex;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
|
|
38
|
-
async function signMessage (signer, messageHex = '0x') {
|
|
39
|
-
return fixSignature(await web3.eth.sign(messageHex, signer));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async function countInstructions (txHash, instruction) {
|
|
43
|
-
const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({
|
|
44
|
-
jsonrpc: '2.0',
|
|
45
|
-
method: 'debug_traceTransaction',
|
|
46
|
-
params: [txHash, {}],
|
|
47
|
-
id: new Date().getTime(),
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const str = JSON.stringify(trace);
|
|
51
|
-
|
|
52
|
-
if (Array.isArray(instruction)) {
|
|
53
|
-
return instruction.map(instr => {
|
|
54
|
-
return str.split('"' + instr.toUpperCase() + '"').length - 1;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return str.split('"' + instruction.toUpperCase() + '"').length - 1;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
module.exports = {
|
|
62
|
-
timeIncreaseTo,
|
|
63
|
-
trackReceivedToken,
|
|
64
|
-
trackReceivedTokenAndTx,
|
|
65
|
-
fixSignature,
|
|
66
|
-
signMessage,
|
|
67
|
-
countInstructions,
|
|
68
|
-
};
|
package/utils/contract.hbs
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# {{{name}}}
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
{{{natspec.title}}}
|
|
5
|
-
{{{natspec.userdoc}}}
|
|
6
|
-
{{{natspec.devdoc}}}
|
|
7
|
-
|
|
8
|
-
{{#if (withoutFirstElement inheritance)}}
|
|
9
|
-
## Derives
|
|
10
|
-
{{/if}}
|
|
11
|
-
{{#each (withoutFirstElement inheritance)}}
|
|
12
|
-
{{#if (getRelativeDocPath name source.contractsDir source.solcOutput.sources)}}
|
|
13
|
-
- [{{name}}]({{getRelativeDocPath name source.contractsDir source.solcOutput.sources}})
|
|
14
|
-
{{else}}
|
|
15
|
-
- {{name}}
|
|
16
|
-
{{/if}}
|
|
17
|
-
{{/each}}
|
|
18
|
-
|
|
19
|
-
{{#if ownFunctions}}
|
|
20
|
-
## Functions
|
|
21
|
-
{{/if}}
|
|
22
|
-
{{#ownFunctions}}
|
|
23
|
-
### {{name}}
|
|
24
|
-
```solidity
|
|
25
|
-
function {{name}}(
|
|
26
|
-
{{#args}}
|
|
27
|
-
{{type}} {{name}}{{#if @last}}{{else}},{{/if}}
|
|
28
|
-
{{/args}}
|
|
29
|
-
) {{visibility}}{{#if outputs}} returns ({{outputs}}){{/if}}
|
|
30
|
-
```
|
|
31
|
-
{{#if natspec.userdoc}}{{natspec.userdoc}}{{/if}}
|
|
32
|
-
{{#if natspec.devdoc}}{{natspec.devdoc}}{{/if}}
|
|
33
|
-
{{#if args}}
|
|
34
|
-
#### Parameters:
|
|
35
|
-
| Name | Type | Description |
|
|
36
|
-
| :--- | :--- | :------------------------------------------------------------------- |
|
|
37
|
-
{{#args}}
|
|
38
|
-
|`{{name}}` | {{type}} | {{#with (lookup ../natspec.params @index)~}} {{ removeNewlines description }} {{/with}}
|
|
39
|
-
{{/args}}{{/if}}
|
|
40
|
-
{{#if natspec.returns}}
|
|
41
|
-
#### Return Values:
|
|
42
|
-
| Name | Type | Description |
|
|
43
|
-
| :----------------------------- | :------------ | :--------------------------------------------------------------------------- |
|
|
44
|
-
{{#natspec.returns}}
|
|
45
|
-
|`{{param}}`| {{#lookup ../outputs.types @index}}{{/lookup}} | {{{removeNewlines description}}}
|
|
46
|
-
{{/natspec.returns}}{{/if}}
|
|
47
|
-
{{/ownFunctions}}
|
|
48
|
-
{{#if ownEvents}}
|
|
49
|
-
## Events
|
|
50
|
-
{{/if}}
|
|
51
|
-
{{#ownEvents}}
|
|
52
|
-
### {{name}}
|
|
53
|
-
```solidity
|
|
54
|
-
event {{name}}(
|
|
55
|
-
{{#args}}
|
|
56
|
-
{{type}} {{name}}{{#if @last}}{{else}},{{/if}}
|
|
57
|
-
{{/args}}
|
|
58
|
-
)
|
|
59
|
-
```
|
|
60
|
-
{{#if natspec.userdoc}}{{natspec.userdoc}}{{/if}}
|
|
61
|
-
{{#if natspec.devdoc}}{{natspec.devdoc}}{{/if}}
|
|
62
|
-
{{#if args}}
|
|
63
|
-
#### Parameters:
|
|
64
|
-
| Name | Type | Description |
|
|
65
|
-
| :--- | :--- | :------------------------------------------------------------------- |
|
|
66
|
-
{{#args}}
|
|
67
|
-
|`{{name}}` | {{type}} | {{#with (lookup ../natspec.params @index)~}} {{ removeNewlines description }} {{/with}}
|
|
68
|
-
{{/args}}{{/if}}
|
|
69
|
-
{{/ownEvents}}
|
package/utils/docify.utils.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const SOLC_NPM_NAME = 'solc';
|
|
3
|
-
const BASE_DIR = 'docgen';
|
|
4
|
-
const SCRIPT_DIR = __dirname;
|
|
5
|
-
const INPUT_DIR = 'contracts';
|
|
6
|
-
const OUTPUT_DIR = `${BASE_DIR}/docs`;
|
|
7
|
-
const HELPERS_PATH = `${SCRIPT_DIR}/solidity-docgen-helpers.js`;
|
|
8
|
-
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const spawn = require('cross-spawn');
|
|
12
|
-
|
|
13
|
-
function getFileNameWithoutExtension (fileName) {
|
|
14
|
-
return fileName.substr(0, fileName.lastIndexOf('.'));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function runProcess (name, args) {
|
|
18
|
-
console.log(`running ${name} with args ${JSON.stringify(args)}`);
|
|
19
|
-
const result = spawn.sync(name, args, { stdio: ['inherit', 'inherit', 'pipe'] });
|
|
20
|
-
if (result.stderr.length > 0) {
|
|
21
|
-
throw new Error(result.stderr);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function getReadmes (targetPath) {
|
|
26
|
-
let result = [];
|
|
27
|
-
const readmePath = path.join(targetPath, 'README.md');
|
|
28
|
-
if (!fs.existsSync(readmePath)) {
|
|
29
|
-
const content = `# ${path.basename(targetPath)}\n`;
|
|
30
|
-
result.push({ path: readmePath, content });
|
|
31
|
-
}
|
|
32
|
-
const childDirs = fs.readdirSync(targetPath, { withFileTypes: true }).filter(item => item.isDirectory());
|
|
33
|
-
for (const dir of childDirs) {
|
|
34
|
-
result = result.concat(getReadmes(path.join(targetPath, dir.name)));
|
|
35
|
-
}
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function generateReadmes (readmes) {
|
|
40
|
-
for (const readme of readmes) {
|
|
41
|
-
fs.writeFileSync(readme.path, readme.content);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function getSummary (targetPath) {
|
|
46
|
-
function getSummaryRoot (summaryTargetPath, indentation) {
|
|
47
|
-
function specialCaseRoot (item) {
|
|
48
|
-
if (item.indentation >= 0) {
|
|
49
|
-
return item;
|
|
50
|
-
}
|
|
51
|
-
return ({
|
|
52
|
-
name: 'Main Readme',
|
|
53
|
-
path: item.path,
|
|
54
|
-
indentation: 0,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const items = fs.readdirSync(summaryTargetPath, { withFileTypes: true });
|
|
59
|
-
let result = [specialCaseRoot({
|
|
60
|
-
name: path.basename(summaryTargetPath),
|
|
61
|
-
path: path.relative(targetPath, path.join(summaryTargetPath, 'README.md')).replaceAll('\\', '/'),
|
|
62
|
-
indentation: indentation - 1,
|
|
63
|
-
})];
|
|
64
|
-
for (const dir of items.filter(item => item.isDirectory())) {
|
|
65
|
-
result = result.concat(getSummaryRoot(path.join(summaryTargetPath, dir.name), indentation + 1));
|
|
66
|
-
}
|
|
67
|
-
result = result
|
|
68
|
-
.concat(items
|
|
69
|
-
.filter(item => !item.isDirectory() &&
|
|
70
|
-
!item.name.endsWith('README.md') &&
|
|
71
|
-
!item.name.endsWith('SUMMARY.md'))
|
|
72
|
-
.map(file => ({
|
|
73
|
-
name: getFileNameWithoutExtension(file.name),
|
|
74
|
-
path: path.relative(targetPath, path.join(summaryTargetPath, file.name)).replaceAll('\\', '/'),
|
|
75
|
-
indentation,
|
|
76
|
-
})));
|
|
77
|
-
return result;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function generateContent (summaryTree) {
|
|
81
|
-
const lines = summaryTree.map(x => `${'\t'.repeat(x.indentation)}* [${x.name}](${x.path})`).join('\n');
|
|
82
|
-
return `# Table of contents\n\n${lines}`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return generateContent(getSummaryRoot(targetPath, 0));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function generateSummary (targetPath, summary) {
|
|
89
|
-
fs.writeFileSync(path.join(targetPath, 'SUMMARY.md'), summary);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function generateGitbookFiles () {
|
|
93
|
-
fs.copyFileSync(path.join(BASE_DIR, 'README.md'), path.join(OUTPUT_DIR, 'README.md'));
|
|
94
|
-
const readmesToGenerate = getReadmes(OUTPUT_DIR);
|
|
95
|
-
const summary = getSummary(OUTPUT_DIR);
|
|
96
|
-
|
|
97
|
-
generateReadmes(readmesToGenerate);
|
|
98
|
-
generateSummary(OUTPUT_DIR, summary);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function removeUnwantedDocs () {
|
|
102
|
-
const unwantedDirs = ['mocks', 'tests'];
|
|
103
|
-
for (const unwantedDir of unwantedDirs) {
|
|
104
|
-
fs.rmSync(path.join(OUTPUT_DIR, unwantedDir), { force: true, recursive: true });
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const solidityDocgenArgs = [
|
|
109
|
-
'solidity-docgen',
|
|
110
|
-
'-i',
|
|
111
|
-
INPUT_DIR,
|
|
112
|
-
'-o',
|
|
113
|
-
OUTPUT_DIR,
|
|
114
|
-
'--solc-module',
|
|
115
|
-
SOLC_NPM_NAME,
|
|
116
|
-
'--solc-settings',
|
|
117
|
-
JSON.stringify({ optimizer: { enabled: false } }),
|
|
118
|
-
'--templates',
|
|
119
|
-
SCRIPT_DIR,
|
|
120
|
-
'--helpers',
|
|
121
|
-
HELPERS_PATH,
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
fs.rmSync(OUTPUT_DIR, { force: true, recursive: true });
|
|
125
|
-
runProcess('npx', solidityDocgenArgs);
|
|
126
|
-
generateGitbookFiles();
|
|
127
|
-
removeUnwantedDocs();
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
removeNewlines (str) {
|
|
3
|
-
return str.replace(/\r?\n/g, ' ');
|
|
4
|
-
},
|
|
5
|
-
withoutFirstElement (arr) {
|
|
6
|
-
return arr.splice(1);
|
|
7
|
-
},
|
|
8
|
-
getRelativeDocPath (contractName, contractsDir, sources) {
|
|
9
|
-
function getRelativePath (contractPath) {
|
|
10
|
-
if (contractPath.startsWith(contractsDir)) {
|
|
11
|
-
return contractPath.substr(contractsDir.length + 1).replace('.sol', '.md');
|
|
12
|
-
}
|
|
13
|
-
if (contractPath.startsWith('@openzeppelin')) {
|
|
14
|
-
const regexMatch = contractPath.match(/@openzeppelin\/contracts\/(.+)\/([^/]+)\.sol/);
|
|
15
|
-
return `https://docs.openzeppelin.com/contracts/3.x/api/${regexMatch[1]}#${regexMatch[2]}`;
|
|
16
|
-
}
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const sourcesKeys = Object.keys(sources);
|
|
21
|
-
const contractPath = sourcesKeys.find(x => x.includes(contractName));
|
|
22
|
-
return getRelativePath(contractPath);
|
|
23
|
-
},
|
|
24
|
-
};
|