Skip to content

Commit 6a74179

Browse files
committed
deprecate + unit test for verifyCallResultFromTarget
1 parent bd60fec commit 6a74179

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

contracts/utils/Address.sol

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -130,21 +130,24 @@ library Address {
130130
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
131131
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
132132
* of an unsuccessful call.
133+
*
134+
* NOTE: This function is DEPRECATED and may be remove in the next major release.
133135
*/
134136
function verifyCallResultFromTarget(
135137
address target,
136138
bool success,
137139
bytes memory returndata
138140
) internal view returns (bytes memory) {
139-
if (!success) {
140-
_revert(returndata);
141-
} else {
142-
// only check if target is a contract if the call was successful and the return data is empty
143-
// otherwise we already know that it was a contract
144-
if (returndata.length == 0 && target.code.length == 0) {
145-
revert AddressEmptyCode(target);
146-
}
141+
// only check if target is a contract if the call was successful and the return data is empty
142+
// otherwise we already know that it was a contract
143+
if (success && (returndata.length > 0 || target.code.length > 0)) {
147144
return returndata;
145+
} else if (success) {
146+
revert AddressEmptyCode(target);
147+
} else if (returndata.length > 0) {
148+
LowLevelCall.bubbleRevert(returndata);
149+
} else {
150+
revert Errors.FailedCall();
148151
}
149152
}
150153

@@ -153,19 +156,9 @@ library Address {
153156
* revert reason or with a default {Errors.FailedCall} error.
154157
*/
155158
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
156-
if (!success) {
157-
_revert(returndata);
158-
} else {
159+
if (success) {
159160
return returndata;
160-
}
161-
}
162-
163-
/**
164-
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
165-
*/
166-
function _revert(bytes memory returndata) private pure {
167-
// Look for revert reason and bubble it up if present
168-
if (returndata.length > 0) {
161+
} else if (returndata.length > 0) {
169162
LowLevelCall.bubbleRevert(returndata);
170163
} else {
171164
revert Errors.FailedCall();

test/utils/Address.test.js

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
55

66
const coder = ethers.AbiCoder.defaultAbiCoder();
77

8+
const fakeContract = { interface: ethers.Interface.from(['error SomeCustomErrorWithoutArgs()']) };
9+
const returndata = fakeContract.interface.encodeErrorResult('SomeCustomErrorWithoutArgs');
10+
811
async function fixture() {
912
const [recipient, other] = await ethers.getSigners();
1013

@@ -274,8 +277,56 @@ describe('Address', function () {
274277

275278
describe('verifyCallResult', function () {
276279
it('returns returndata on success', async function () {
277-
const returndata = '0x123abc';
278-
expect(await this.mock.$verifyCallResult(true, returndata)).to.equal(returndata);
280+
await expect(this.mock.$verifyCallResult(true, returndata)).to.eventually.equal(returndata);
281+
});
282+
283+
it('bubble returndata on failure', async function () {
284+
await expect(this.mock.$verifyCallResult(false, returndata)).to.be.revertedWithCustomError(
285+
fakeContract,
286+
'SomeCustomErrorWithoutArgs',
287+
);
288+
});
289+
290+
it('standard error on failure without returndata', async function () {
291+
await expect(this.mock.$verifyCallResult(false, '0x')).to.be.revertedWithCustomError(this.mock, 'FailedCall');
292+
});
293+
});
294+
295+
describe('verifyCallResultFromTarget', function () {
296+
it('success with non-empty returndata', async function () {
297+
await expect(this.mock.$verifyCallResultFromTarget(this.mock, true, returndata)).to.eventually.equal(returndata);
298+
await expect(this.mock.$verifyCallResultFromTarget(this.recipient, true, returndata)).to.eventually.equal(
299+
returndata,
300+
);
301+
});
302+
303+
it('success with empty returndata', async function () {
304+
await expect(this.mock.$verifyCallResultFromTarget(this.mock, true, '0x')).to.eventually.equal('0x');
305+
await expect(this.mock.$verifyCallResultFromTarget(this.recipient, true, '0x'))
306+
.to.be.revertedWithCustomError(this.mock, 'AddressEmptyCode')
307+
.withArgs(this.recipient);
308+
});
309+
310+
it('failure with non-empty returndata', async function () {
311+
await expect(this.mock.$verifyCallResultFromTarget(this.mock, false, returndata)).to.revertedWithCustomError(
312+
fakeContract,
313+
'SomeCustomErrorWithoutArgs',
314+
);
315+
await expect(this.mock.$verifyCallResultFromTarget(this.recipient, false, returndata)).to.revertedWithCustomError(
316+
fakeContract,
317+
'SomeCustomErrorWithoutArgs',
318+
);
319+
});
320+
321+
it('failure with empty returndata', async function () {
322+
await expect(this.mock.$verifyCallResultFromTarget(this.mock, false, '0x')).to.be.revertedWithCustomError(
323+
this.mock,
324+
'FailedCall',
325+
);
326+
await expect(this.mock.$verifyCallResultFromTarget(this.recipient, false, '0x')).to.be.revertedWithCustomError(
327+
this.mock,
328+
'FailedCall',
329+
);
279330
});
280331
});
281332
});

0 commit comments

Comments
 (0)