Skip to content

Commit defa881

Browse files
authored
Fix Hardhat compile error when fallback or receive functions are present (#1060)
1 parent 49e7ae9 commit defa881

File tree

6 files changed

+93
-25
lines changed

6 files changed

+93
-25
lines changed

packages/core/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.35.1 (2024-08-13)
4+
5+
- Fix Hardhat compile error when `fallback` or `receive` functions are present. ([#1060](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1060))
6+
37
## 1.35.0 (2024-07-31)
48

59
- Fix Hardhat compile error when public variables are used to implement interface functions. ([#1055](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1055))

packages/core/contracts/test/NamespacedToModify.sol

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ contract Example {
8383
}
8484

8585
contract HasFunction {
86-
constructor(uint) {}
86+
/// @param myInt an integer
87+
constructor(uint myInt) {}
88+
8789
function foo() pure public returns (uint) {}
8890
}
8991

@@ -285,4 +287,21 @@ contract HasExternalViewFunction is IHasExternalViewFunction {
285287

286288
contract DeploysContractToImmutable {
287289
HasFunction public immutable example = new HasFunction(1);
290+
}
291+
292+
contract HasSpecialFunctions {
293+
/// @param data call data
294+
/// @return dataReturn returned data
295+
fallback(bytes calldata data) external returns (bytes memory dataReturn) {
296+
return data;
297+
}
298+
299+
receive() external payable {
300+
}
301+
302+
// Regular function but payable
303+
function hasPayable() public payable {
304+
}
305+
306+
bytes4 constant PAYABLE_SELECTOR = this.hasPayable.selector;
288307
}

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openzeppelin/upgrades-core",
3-
"version": "1.35.0",
3+
"version": "1.35.1",
44
"description": "",
55
"repository": "https://github.com/OpenZeppelin/openzeppelin-upgrades/tree/master/packages/core",
66
"license": "MIT",

packages/core/src/utils/make-namespaced.test.ts.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ Generated by [AVA](https://avajs.dev).
9797
9898
abstract contract HasFunction {␊
9999
100+
enum $astId_id_random { dummy }␊
101+
100102
function foo() pure public returns (bool) {}␊
101103
}␊
102104
@@ -228,6 +230,19 @@ Generated by [AVA](https://avajs.dev).
228230
229231
abstract contract DeploysContractToImmutable {␊
230232
enum $astId_id_random { dummy }␊
233+
}␊
234+
235+
abstract contract HasSpecialFunctions {␊
236+
237+
238+
enum $astId_id_random { dummy }␊
239+
240+
enum $astId_id_random { dummy }␊
241+
242+
// Regular function but payable␊
243+
function hasPayable() public payable {}␊
244+
245+
bytes4 constant PAYABLE_SELECTOR = this.hasPayable.selector;␊
231246
}`,
232247
},
233248
'contracts/test/NamespacedToModifyImported.sol': {
@@ -344,7 +359,9 @@ Generated by [AVA](https://avajs.dev).
344359
}␊
345360
346361
abstract contract HasFunction {␊
347-
362+
/// @param myInt an integer␊
363+
enum $astId_id_random { dummy }␊
364+
348365
function foo() pure public returns (bool) {}␊
349366
}␊
350367
@@ -517,6 +534,19 @@ Generated by [AVA](https://avajs.dev).
517534
518535
abstract contract DeploysContractToImmutable {␊
519536
enum $astId_id_random { dummy }␊
537+
}␊
538+
539+
abstract contract HasSpecialFunctions {␊
540+
/// @param data call data␊
541+
/// @return dataReturn returned data␊
542+
enum $astId_id_random { dummy }␊
543+
544+
enum $astId_id_random { dummy }␊
545+
546+
// Regular function but payable␊
547+
function hasPayable() public payable {}␊
548+
549+
bytes4 constant PAYABLE_SELECTOR = this.hasPayable.selector;␊
520550
}`,
521551
},
522552
'contracts/test/NamespacedToModifyImported.sol': {
@@ -559,7 +589,7 @@ Generated by [AVA](https://avajs.dev).
559589
pragma solidity 0.7.6;␊
560590
561591
abstract contract HasFunction {␊
562-
592+
enum $astId_id_random { dummy }
563593
function foo() pure public returns (bool) {}␊
564594
}␊
565595
117 Bytes
Binary file not shown.

packages/core/src/utils/make-namespaced.ts

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { isNodeType } from 'solidity-ast/utils';
22
import { Node } from 'solidity-ast/node';
33
import { SolcInput, SolcOutput } from '../solc-api';
44
import { getStorageLocationAnnotation } from '../storage/namespace';
5-
import { assert } from './assert';
5+
import { assert, assertUnreachable } from './assert';
66
import { FunctionDefinition, VariableDeclaration } from 'solidity-ast';
77

88
const OUTPUT_SELECTION = {
@@ -18,9 +18,13 @@ const OUTPUT_SELECTION = {
1818
*
1919
* This makes the following modifications to the input:
2020
* - Adds a state variable for each namespaced struct definition
21-
* - For each contract, for all node types that are not needed for storage layout or may reference deleted functions and constructors, converts them to dummy enums with random id
21+
* - For each contract, for all node types that are not needed for storage layout or may call functions and constructors, converts them to dummy enums with random id
2222
* - Converts all using for directives (at file level and in contracts) to dummy enums with random id (do not delete them to avoid orphaning possible NatSpec documentation)
23-
* - Converts all custom errors, free functions and constants (at file level) to dummy enums with the same name (do not delete them since they might be imported by other files)
23+
* - Converts all custom errors and constants (at file level) to dummy enums with the same name (do not delete them since they might be imported by other files)
24+
* - Replaces functions as follows:
25+
* - For regular function and free function, keep declarations since they may be referenced by constants (free functions may also be imported by other files). But simplify compilation by removing modifiers and body, and replace return parameters with bools which can be default initialized.
26+
* - Constructors are not needed, since we removed anything that may call constructors. Convert to dummy enums to avoid orphaning possible NatSpec.
27+
* - Fallback and receive functions are not needed, since they don't have signatures. Convert to dummy enums to avoid orphaning possible NatSpec.
2428
*
2529
* Also sets the outputSelection to only include storageLayout and ast, since the other outputs are not needed.
2630
*
@@ -228,28 +232,39 @@ function toDummyEnumWithAstId(astId: number) {
228232
}
229233

230234
function replaceFunction(node: FunctionDefinition, orig: Buffer, modifications: Modification[]) {
231-
if (node.kind === 'constructor') {
232-
modifications.push(makeDelete(node, orig));
233-
} else {
234-
if (node.modifiers.length > 0) {
235-
for (const modifier of node.modifiers) {
236-
modifications.push(makeDelete(modifier, orig));
235+
switch (node.kind) {
236+
case 'freeFunction':
237+
case 'function': {
238+
if (node.modifiers.length > 0) {
239+
for (const modifier of node.modifiers) {
240+
modifications.push(makeDelete(modifier, orig));
241+
}
237242
}
238-
}
239243

240-
if (node.returnParameters.parameters.length > 0) {
241-
modifications.push(
242-
makeReplace(
243-
node.returnParameters,
244-
orig,
245-
`(${node.returnParameters.parameters.map(param => toReturnParameterReplacement(param)).join(', ')})`,
246-
),
247-
);
248-
}
244+
if (node.returnParameters.parameters.length > 0) {
245+
modifications.push(
246+
makeReplace(
247+
node.returnParameters,
248+
orig,
249+
`(${node.returnParameters.parameters.map(param => toReturnParameterReplacement(param)).join(', ')})`,
250+
),
251+
);
252+
}
253+
254+
if (node.body) {
255+
modifications.push(makeReplace(node.body, orig, '{}'));
256+
}
249257

250-
if (node.body) {
251-
modifications.push(makeReplace(node.body, orig, '{}'));
258+
break;
259+
}
260+
case 'constructor':
261+
case 'fallback':
262+
case 'receive': {
263+
modifications.push(makeReplace(node, orig, toDummyEnumWithAstId(node.id)));
264+
break;
252265
}
266+
default:
267+
return assertUnreachable(node.kind);
253268
}
254269
}
255270

0 commit comments

Comments
 (0)