Skip to content

Commit

Permalink
Merge pull request #134 from 1inch/feature/cheaperEthSend
Browse files Browse the repository at this point in the history
[SC-1103] add cheapEthSender
  • Loading branch information
ZumZoom authored Apr 2, 2024
2 parents 98259b2 + 217d34b commit ef05c02
Show file tree
Hide file tree
Showing 14 changed files with 1,103 additions and 1,327 deletions.
18 changes: 18 additions & 0 deletions contracts/mixins/SelfdestructEthSender.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.25;


abstract contract SelfdestructEthSender {
constructor() {
// tload is done to verify that the EVM is cancun-compatible
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
pop(tload(0))
}
}

function stopAndTransferBalance(address payable receiver) external {
selfdestruct(receiver);
}
}
17 changes: 17 additions & 0 deletions contracts/mocks/SelfdestructEthSenderMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.25;

import "../mixins/SelfdestructEthSender.sol";

contract SelfdestructEthSenderMock is SelfdestructEthSender {
error ETHTransferFailed();

receive() external payable {}

function transferBalance(address payable receiver) external payable {
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = receiver.call{value: address(this).balance}("");
if (!success) revert ETHTransferFailed();
}
}
3 changes: 3 additions & 0 deletions contracts/tests/mocks/WETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ contract WETH {
}

function withdraw(uint256 wad) public {
// solhint-disable-next-line gas-custom-errors
require(balanceOf[msg.sender] >= wad, "Not enough balance");
balanceOf[msg.sender] -= wad;
payable(msg.sender).transfer(wad);
Expand All @@ -50,9 +51,11 @@ contract WETH {
public
returns (bool)
{
// solhint-disable-next-line gas-custom-errors
require(balanceOf[src] >= wad, "Not enough balance");

if (src != msg.sender && allowance[src][msg.sender] != type(uint).max) {
// solhint-disable-next-line gas-custom-errors
require(allowance[src][msg.sender] >= wad, "Not enough allowance");
allowance[src][msg.sender] -= wad;
}
Expand Down
2 changes: 2 additions & 0 deletions docs/contracts/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
* [EthReceiver](mixins/EthReceiver.md)
* [OnlyWethReceiver](mixins/OnlyWethReceiver.md)
* [PermitAndCall](mixins/PermitAndCall.md)
* [SelfdestructEthSender](mixins/SelfdestructEthSender.md)
* [mocks](mocks/README.md)
* [ERC20PermitMock](mocks/ERC20PermitMock.md)
* [SelfdestructEthSenderMock](mocks/SelfdestructEthSenderMock.md)
* [TokenCustomDecimalsMock](mocks/TokenCustomDecimalsMock.md)
* [TokenMock](mocks/TokenMock.md)
* [tests](tests/README.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/contracts/mixins/PermitAndCall.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ PermitAndCall


Abstract contract to support permit and action execution in a single transaction.
Allows tokens that implement EIP-2612 permits, DAI-like permits and Permit2 to be approved and spent in a single transaction.
Allows tokens that implement EIP-2612 permits, DAI-like permits, USDC-like permits and Permit2 to be approved and spent in a single transaction.


## Functions
Expand Down
32 changes: 32 additions & 0 deletions docs/contracts/mixins/SelfdestructEthSender.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SelfdestructEthSender







## Functions
### constructor
```solidity
function constructor(
) internal
```




### stopAndTransferBalance
```solidity
function stopAndTransferBalance(
address payable receiver
) external
```


#### Parameters:
| Name | Type | Description |
| :--- | :--- | :------------------------------------------------------------------- |
|`receiver` | address payable |


5 changes: 2 additions & 3 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import '@typechain/hardhat';
import '@nomicfoundation/hardhat-ethers';
import '@nomicfoundation/hardhat-chai-matchers';
import 'hardhat-gas-reporter';
import 'hardhat-tracer';
import 'hardhat-deploy';
import '@nomicfoundation/hardhat-verify';
require('solidity-coverage'); // require because no TS typings available
Expand All @@ -23,13 +22,13 @@ const { networks, etherscan } = new Networks();

const config: HardhatUserConfig = {
solidity: {
version: '0.8.23',
version: '0.8.25',
settings: {
optimizer: {
enabled: true,
runs: 1000000,
},
evmVersion: (networks[getNetwork()] as HardhatNetworkUserConfig)?.hardfork || 'shanghai',
evmVersion: (networks[getNetwork()] as HardhatNetworkUserConfig)?.hardfork || 'cancun',
viaIR: true,
},
},
Expand Down
33 changes: 16 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,47 +38,46 @@
"@metamask/eth-sig-util": "7.0.1",
"@nomicfoundation/hardhat-ethers": "3.0.5",
"@nomicfoundation/hardhat-network-helpers": "1.0.10",
"@nomicfoundation/hardhat-verify": "2.0.4",
"@openzeppelin/contracts": "5.0.1",
"@nomicfoundation/hardhat-verify": "2.0.5",
"@openzeppelin/contracts": "5.0.2",
"@uniswap/permit2-sdk": "1.2.0",
"chai": "4.4.0",
"dotenv": "16.4.3",
"dotenv": "16.4.5",
"ethereumjs-util": "7.1.5",
"ethers": "6.11.0",
"hardhat": "2.19.5",
"hardhat-deploy": "0.11.45",
"ethers": "6.11.1",
"hardhat": "2.22.2",
"hardhat-deploy": "0.12.2",
"mocha-chai-jest-snapshot": "1.1.4"
},
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "2.0.4",
"@nomicfoundation/hardhat-chai-matchers": "2.0.6",
"@typechain/ethers-v6": "0.5.1",
"@typechain/hardhat": "9.1.0",
"@types/mocha": "10.0.6",
"@typescript-eslint/eslint-plugin": "7.0.1",
"@typescript-eslint/parser": "7.0.1",
"@typescript-eslint/eslint-plugin": "7.4.0",
"@typescript-eslint/parser": "7.4.0",
"acquit": "1.3.0",
"commander": "12.0.0",
"create-ts-index": "1.14.0",
"cross-spawn": "7.0.3",
"eslint": "8.56.0",
"eslint": "8.57.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-n": "16.6.2",
"eslint-plugin-promise": "6.1.1",
"hardhat-gas-reporter": "1.0.10",
"hardhat-tracer": "2.7.0",
"hardhat-gas-reporter": "2.0.2",
"prettier": "3.2.5",
"prettier-plugin-solidity": "1.3.1",
"rimraf": "5.0.5",
"solc": "0.8.23",
"solhint": "4.1.1",
"solidity-coverage": "0.8.7",
"solc": "0.8.25",
"solhint": "4.5.2",
"solidity-coverage": "0.8.11",
"solidity-docgen": "0.5.17",
"ts-node": "10.9.2",
"typechain": "8.3.2",
"typedoc": "0.25.8",
"typedoc": "0.25.12",
"typedoc-plugin-markdown": "3.17.1",
"typescript": "5.3.3"
"typescript": "5.4.3"
},
"bin": {
"solidity-utils-docify": "utils/docify.utils.js",
Expand Down
38 changes: 38 additions & 0 deletions test/contracts/SelfdestructEthSender.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { expect } from '../../src/expect';
import { ether } from '../../src/prelude';
import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers';
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
import { ethers } from 'hardhat';

describe('SelfdestructEthSender', function () {
let signer0: SignerWithAddress;
let signer1: SignerWithAddress;

before(async function () {
[signer0, signer1] = await ethers.getSigners();
});

async function deployMocks() {
const EthSender = await ethers.getContractFactory('SelfdestructEthSenderMock');
const ethSender = await EthSender.deploy();

return { ethSender };
}

it('should send Ethers with selfdestruct', async function () {
const { ethSender } = await loadFixture(deployMocks);
const ethSenderAddress = await ethSender.getAddress();

await signer0.sendTransaction({ to: ethSenderAddress, value: ether('1') });
const receipt0 = await (await ethSender.transferBalance(signer1.address)).wait();
console.log('send ethers without selfdestruct', receipt0!.gasUsed.toString());

await signer0.sendTransaction({ to: ethSenderAddress, value: ether('1') });
const balanceOfAddr1 = await ethers.provider.getBalance(signer1.address);
const receipt1 = await (await ethSender.stopAndTransferBalance(signer1.address)).wait();
console.log('send all ethers', receipt1!.gasUsed.toString());
expect(await ethers.provider.getBalance(signer1.address)).to.be.eq(balanceOfAddr1 + ether('1'));
expect(await ethers.provider.getBalance(ethSenderAddress)).to.be.eq(ether('0'));
expect(await ethers.provider.getCode(ethSenderAddress)).to.be.not.eq('0x');
});
});
6 changes: 3 additions & 3 deletions test/contracts/__snapshots__/BytesMemory.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

exports[`BytesMemoryMock Gas usage slice 1`] = `22433n`;

exports[`BytesMemoryMock Gas usage unwrap 32 bytes 1`] = `23012n`;
exports[`BytesMemoryMock Gas usage unwrap 32 bytes 1`] = `22919n`;

exports[`BytesMemoryMock Gas usage unwrap 33 bytes 1`] = `23363n`;
exports[`BytesMemoryMock Gas usage unwrap 33 bytes 1`] = `23196n`;

exports[`BytesMemoryMock Gas usage unwrap 64 bytes 1`] = `23726n`;
exports[`BytesMemoryMock Gas usage unwrap 64 bytes 1`] = `23559n`;
28 changes: 14 additions & 14 deletions test/contracts/__snapshots__/StringUtil.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`StringUtil Gas usage Empty bytes 1`] = `22305n`;
exports[`StringUtil Gas usage Empty bytes 1`] = `22212n`;

exports[`StringUtil Gas usage Empty bytes naive 1`] = `22651n`;
exports[`StringUtil Gas usage Empty bytes naive 1`] = `22558n`;

exports[`StringUtil Gas usage Extremely long byte array gas 1`] = `60428n`;
exports[`StringUtil Gas usage Extremely long byte array gas 1`] = `55747n`;

exports[`StringUtil Gas usage Extremely long byte array gas naive 1`] = `536349n`;
exports[`StringUtil Gas usage Extremely long byte array gas naive 1`] = `531668n`;

exports[`StringUtil Gas usage Single byte 1`] = `22982n`;
exports[`StringUtil Gas usage Single byte 1`] = `22889n`;

exports[`StringUtil Gas usage Single byte naive 1`] = `23301n`;
exports[`StringUtil Gas usage Single byte naive 1`] = `23208n`;

exports[`StringUtil Gas usage Uint 128 1`] = `22815n`;
exports[`StringUtil Gas usage Uint 128 1`] = `22574n`;

exports[`StringUtil Gas usage Uint 128 naive 1`] = `38302n`;
exports[`StringUtil Gas usage Uint 128 naive 1`] = `38061n`;

exports[`StringUtil Gas usage Uint 256 1`] = `23007n`;
exports[`StringUtil Gas usage Uint 256 1`] = `22766n`;

exports[`StringUtil Gas usage Uint 256 as bytes 1`] = `23520n`;
exports[`StringUtil Gas usage Uint 256 as bytes 1`] = `23279n`;

exports[`StringUtil Gas usage Uint 256 as bytes naive 1`] = `39097n`;
exports[`StringUtil Gas usage Uint 256 as bytes naive 1`] = `38856n`;

exports[`StringUtil Gas usage Uint 256 naive 1`] = `38494n`;
exports[`StringUtil Gas usage Uint 256 naive 1`] = `38253n`;

exports[`StringUtil Gas usage Very long byte array gas 1`] = `25412n`;
exports[`StringUtil Gas usage Very long byte array gas 1`] = `25023n`;

exports[`StringUtil Gas usage Very long byte array gas naive 1`] = `57177n`;
exports[`StringUtil Gas usage Very long byte array gas naive 1`] = `56788n`;
Empty file modified utils/file-dependencies.js
100644 → 100755
Empty file.
Empty file modified utils/test-docgen.js
100644 → 100755
Empty file.
Loading

0 comments on commit ef05c02

Please sign in to comment.