@1inch/solidity-utils 1.2.0 → 1.2.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/js/profileEVM.js CHANGED
@@ -1,84 +1,88 @@
1
- const { promisify } = require('util');
2
- const fs = require('fs').promises;
3
-
4
- function _normalizeOp (op) {
5
- if (op.op === 'STATICCALL') {
6
- if (op.stack.length > 8 && op.stack[op.stack.length - 8] === '0000000000000000000000000000000000000000000000000000000000000001') {
7
- op.gasCost = 700 + 3000;
8
- op.op = 'STATICCALL-ECRECOVER';
9
- } else if (op.stack.length > 8 && op.stack[op.stack.length - 8] <= '00000000000000000000000000000000000000000000000000000000000000FF') {
10
- op.gasCost = 700;
11
- op.op = 'STATICCALL-' + op.stack[op.stack.length - 8].substr(62, 2);
12
- } else {
13
- op.gasCost = 700;
14
- }
15
- }
16
- if (['CALL', 'DELEGATECALL', 'CALLCODE'].indexOf(op.op) !== -1) {
17
- op.gasCost = 700;
18
- }
19
- if (['RETURN', 'REVERT', 'INVALID'].indexOf(op.op) !== -1) {
20
- op.gasCost = 3;
21
- }
22
- }
23
-
24
- async function profileEVM (txHash, instruction, optionalTraceFile) {
25
- const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({
26
- jsonrpc: '2.0',
27
- method: 'debug_traceTransaction',
28
- params: [txHash, {}],
29
- id: new Date().getTime(),
30
- });
31
-
32
- const str = JSON.stringify(trace);
33
-
34
- if (optionalTraceFile) {
35
- await fs.writeFile(optionalTraceFile, str);
36
- }
37
-
38
- if (Array.isArray(instruction)) {
39
- return instruction.map(instr => {
40
- return str.split('"' + instr.toUpperCase() + '"').length - 1;
41
- });
42
- }
43
-
44
- return str.split('"' + instruction.toUpperCase() + '"').length - 1;
45
- }
46
-
47
- async function gasspectEVM (txHash, optionalTraceFile) {
48
- const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({
49
- jsonrpc: '2.0',
50
- method: 'debug_traceTransaction',
51
- params: [txHash, {}],
52
- id: new Date().getTime(),
53
- });
54
-
55
- const ops = trace.result.structLogs;
56
-
57
- const traceAddress = [0, -1];
58
- for (const op of ops) {
59
- op.traceAddress = traceAddress.slice(0, traceAddress.length - 1);
60
- _normalizeOp(op);
61
-
62
- if (op.depth + 2 > traceAddress.length) {
63
- traceAddress[traceAddress.length - 1] += 1;
64
- traceAddress.push(-1);
65
- }
66
-
67
- if (op.depth + 2 < traceAddress.length) {
68
- traceAddress.pop();
69
- }
70
- }
71
-
72
- const result = ops.filter(op => op.gasCost > 300).map(op => op.traceAddress.join('-') + '-' + op.op + ' = ' + op.gasCost);
73
-
74
- if (optionalTraceFile) {
75
- await fs.writeFile(optionalTraceFile, JSON.stringify(result));
76
- }
77
-
78
- return result;
79
- }
80
-
81
- module.exports = {
82
- profileEVM,
83
- gasspectEVM,
84
- };
1
+ const { promisify } = require('util');
2
+ const fs = require('fs').promises;
3
+
4
+ function _normalizeOp (op) {
5
+ if (op.op === 'STATICCALL') {
6
+ if (op.stack.length > 8 && op.stack[op.stack.length - 8] === '0000000000000000000000000000000000000000000000000000000000000001') {
7
+ op.gasCost = 700 + 3000;
8
+ op.op = 'STATICCALL-ECRECOVER';
9
+ } else if (op.stack.length > 8 && op.stack[op.stack.length - 8] <= '00000000000000000000000000000000000000000000000000000000000000FF') {
10
+ op.gasCost = 700;
11
+ op.op = 'STATICCALL-' + op.stack[op.stack.length - 8].substr(62, 2);
12
+ } else {
13
+ op.gasCost = 700;
14
+ }
15
+ }
16
+ if (['CALL', 'DELEGATECALL', 'CALLCODE'].indexOf(op.op) !== -1) {
17
+ op.gasCost = 700;
18
+ }
19
+ if (['RETURN', 'REVERT', 'INVALID'].indexOf(op.op) !== -1) {
20
+ op.gasCost = 3;
21
+ }
22
+ }
23
+
24
+ async function profileEVM (txHash, instruction, optionalTraceFile) {
25
+ const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({
26
+ jsonrpc: '2.0',
27
+ method: 'debug_traceTransaction',
28
+ params: [txHash, {}],
29
+ id: new Date().getTime(),
30
+ });
31
+
32
+ const str = JSON.stringify(trace);
33
+
34
+ if (optionalTraceFile) {
35
+ await fs.writeFile(optionalTraceFile, str);
36
+ }
37
+
38
+ if (Array.isArray(instruction)) {
39
+ return instruction.map(instr => {
40
+ return str.split('"' + instr.toUpperCase() + '"').length - 1;
41
+ });
42
+ }
43
+
44
+ return str.split('"' + instruction.toUpperCase() + '"').length - 1;
45
+ }
46
+
47
+ async function gasspectEVM (txHash, options = {}, optionalTraceFile) {
48
+ const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({
49
+ jsonrpc: '2.0',
50
+ method: 'debug_traceTransaction',
51
+ params: [txHash, {}],
52
+ id: new Date().getTime(),
53
+ });
54
+
55
+ const ops = trace.result.structLogs;
56
+
57
+ const traceAddress = [0, -1];
58
+ for (const op of ops) {
59
+ op.traceAddress = traceAddress.slice(0, traceAddress.length - 1);
60
+ _normalizeOp(op);
61
+
62
+ if (op.depth + 2 > traceAddress.length) {
63
+ traceAddress[traceAddress.length - 1] += 1;
64
+ traceAddress.push(-1);
65
+ }
66
+
67
+ if (op.depth + 2 < traceAddress.length) {
68
+ traceAddress.pop();
69
+ }
70
+ }
71
+
72
+ const minOpGasCost = options.minOpGasCost ? options.minOpGasCost : 300;
73
+ const result = ops.filter(op => op.gasCost > minOpGasCost).map(op => op.traceAddress.join('-') + '-' + op.op +
74
+ (options.args ? '(' + (op.args || []).join(',') + ')' : '') +
75
+ (options.res ? (op.res ? ':0x' + op.res : '') : '') +
76
+ ' = ' + op.gasCost);
77
+
78
+ if (optionalTraceFile) {
79
+ await fs.writeFile(optionalTraceFile, JSON.stringify(result));
80
+ }
81
+
82
+ return result;
83
+ }
84
+
85
+ module.exports = {
86
+ profileEVM,
87
+ gasspectEVM,
88
+ };
package/js/utils.js CHANGED
@@ -1,68 +1,68 @@
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
- };
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/package.json CHANGED
@@ -1,59 +1,60 @@
1
- {
2
- "name": "@1inch/solidity-utils",
3
- "version": "1.2.0",
4
- "main": "index.js",
5
- "repository": {
6
- "type": "git",
7
- "url": "git+ssh://git@github.com/1inch/solidity-utils.git"
8
- },
9
- "license": "MIT",
10
- "dependencies": {
11
- "@openzeppelin/contracts": "^4.3.2"
12
- },
13
- "devDependencies": {
14
- "@nomiclabs/hardhat-etherscan": "^2.1.6",
15
- "@nomiclabs/hardhat-truffle5": "^2.0.0",
16
- "@nomiclabs/hardhat-web3": "^2.0.0",
17
- "@openzeppelin/test-helpers": "^0.5.13",
18
- "chai": "^4.3.4",
19
- "cross-spawn": "^7.0.3",
20
- "dotenv": "^10.0.0",
21
- "eslint": "^7.32.0",
22
- "eslint-config-standard": "^16.0.3",
23
- "eslint-plugin-import": "^2.24.2",
24
- "eslint-plugin-node": "^11.1.0",
25
- "eslint-plugin-promise": "^5.1.0",
26
- "eslint-plugin-standard": "^5.0.0",
27
- "hardhat": "^2.6.4",
28
- "hardhat-deploy": "^0.9.2",
29
- "hardhat-gas-reporter": "^1.0.4",
30
- "rimraf": "^3.0.2",
31
- "shx": "^0.3.3",
32
- "solc": "^0.8.9",
33
- "solhint": "^3.3.6",
34
- "solidity-coverage": "^0.7.17"
35
- },
36
- "bin": {
37
- "solidity-utils-docify": "utils/docify.utils.js"
38
- },
39
- "scripts": {
40
- "build": "rimraf ./dist && mkdir dist && shx cp -R js ./dist/js && shx cp -R utils ./dist/utils && shx cp package.json ./dist",
41
- "coverage": "hardhat coverage",
42
- "lint": "yarn run lint:js && yarn run lint:sol",
43
- "lint:fix": "yarn run lint:js:fix && yarn run lint:sol:fix",
44
- "lint:js": "eslint .",
45
- "lint:js:fix": "eslint . --fix",
46
- "lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"",
47
- "lint:sol:fix": "solhint --max-warnings 0 \"contracts/**/*.sol\" --fix",
48
- "test": "hardhat test"
49
- },
50
- "bugs": {
51
- "url": "https://github.com/1inch/solidity-utils/issues"
52
- },
53
- "homepage": "https://github.com/1inch/solidity-utils#readme",
54
- "directories": {
55
- "test": "test"
56
- },
57
- "author": "1inch",
58
- "description": ""
59
- }
1
+ {
2
+ "name": "@1inch/solidity-utils",
3
+ "version": "1.2.4",
4
+ "main": "index.js",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+ssh://git@github.com/1inch/solidity-utils.git"
8
+ },
9
+ "license": "MIT",
10
+ "dependencies": {
11
+ "@openzeppelin/contracts": "^4.4.0",
12
+ "ethereumjs-wallet": "^1.0.2"
13
+ },
14
+ "devDependencies": {
15
+ "@nomiclabs/hardhat-etherscan": "^2.1.8",
16
+ "@nomiclabs/hardhat-truffle5": "^2.0.0",
17
+ "@nomiclabs/hardhat-web3": "^2.0.0",
18
+ "@openzeppelin/test-helpers": "^0.5.15",
19
+ "chai": "^4.3.4",
20
+ "cross-spawn": "^7.0.3",
21
+ "dotenv": "^10.0.0",
22
+ "eslint": "^8.3.0",
23
+ "eslint-config-standard": "^16.0.3",
24
+ "eslint-plugin-import": "^2.25.3",
25
+ "eslint-plugin-node": "^11.1.0",
26
+ "eslint-plugin-promise": "^5.1.1",
27
+ "eslint-plugin-standard": "^5.0.0",
28
+ "hardhat": "^2.7.0",
29
+ "hardhat-deploy": "^0.9.14",
30
+ "hardhat-gas-reporter": "^1.0.6",
31
+ "rimraf": "^3.0.2",
32
+ "shx": "^0.3.3",
33
+ "solc": "^0.8.10",
34
+ "solhint": "^3.3.6",
35
+ "solidity-coverage": "^0.7.17"
36
+ },
37
+ "bin": {
38
+ "solidity-utils-docify": "utils/docify.utils.js"
39
+ },
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",
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
+ "bugs": {
52
+ "url": "https://github.com/1inch/solidity-utils/issues"
53
+ },
54
+ "homepage": "https://github.com/1inch/solidity-utils#readme",
55
+ "directories": {
56
+ "test": "test"
57
+ },
58
+ "author": "1inch",
59
+ "description": "Solidity and JS utils"
60
+ }
@@ -1,69 +1,69 @@
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}}
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}}