Skip to content

Commit 73b20c7

Browse files
committed
Problem: dynamic erc20 precompiles are heavy
Closes: #505 re-design bank precompile to support solidity erc20 contract. solc optimize
1 parent 750d77d commit 73b20c7

File tree

5 files changed

+472
-0
lines changed

5 files changed

+472
-0
lines changed

precompiles/bank2/ERC20.bin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
60a06040523461022357610ee28038038061001981610227565b9283398101906040818303126102235780516001600160401b0381116102235781019082601f830112156102235781516001600160401b03811161020f5761006a601f8201601f1916602001610227565b9381855260208285010111610223576020815f92828096018388015e8501015201516001600160a01b03811681036102235781516001600160401b03811161020f575f54600181811c91168015610205575b60208210146101f157601f811161018f575b50602092601f821160011461013057928192935f92610125575b50508160011b915f199060031b1c1916175f555b608052604051610c95908161024d8239608051818181610198015281816106680152610a940152f35b015190505f806100e8565b601f198216935f8052805f20915f5b868110610177575083600195961061015f575b505050811b015f556100fc565b01515f1960f88460031b161c191690555f8080610152565b9192602060018192868501518155019401920161013f565b5f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c810191602084106101e7575b601f0160051c01905b8181106101dc57506100ce565b5f81556001016101cf565b90915081906101c6565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100bc565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761020f5760405256fe60806040526004361015610011575f80fd5b5f3560e01c806306fdde03146100c4578063095ea7b3146100bf57806318160ddd146100ba57806323b872dd146100b5578063313ce567146100b057806370a08231146100ab57806376cdb03b146100a657806395d89b41146100a1578063a9059cbb1461009c578063c370b042146100975763dd62ed3e14610092575f80fd5b61090a565b6108d1565b610704565b61068c565b61061e565b610560565b6104d9565b6103bd565b61033a565b610216565b610112565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080809581815201938051918291828752018686015e5f8582860101520116010190565b346101cc575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc576101c86101bc61016a6101966101546107c6565b6040519283915f6020840152602183019061099b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610780565b7f0000000000000000000000000000000000000000000000000000000000000000610b83565b604051918291826100c9565b0390f35b5f80fd5b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101cc57565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101cc57565b346101cc5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc5761024d6101d0565b602435331561030e5773ffffffffffffffffffffffffffffffffffffffff82169182156102e2576102a88291335f52600160205260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b5560405190815233907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590602090a3602060405160018152f35b7f94280d62000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7fe602df05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346101cc575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc5760206103b061016a61019661037b6107c6565b6040519283917f030000000000000000000000000000000000000000000000000000000000000087840152602183019061099b565b0151604051908152602090f35b346101cc5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc576103f46101d0565b6103fc6101f3565b6044359073ffffffffffffffffffffffffffffffffffffffff83165f5260016020526104493360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8410610489575b61047d93506109ad565b60405160018152602090f35b8284106104a5576104a08361047d95033383610bdb565b610473565b82847ffb8f41b2000000000000000000000000000000000000000000000000000000005f523360045260245260445260645ffd5b346101cc575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc57602061054f61016a61019661051a6107c6565b6040519283917f020000000000000000000000000000000000000000000000000000000000000087840152602183019061099b565b01516040515f9190911a8152602090f35b346101cc5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc576101c8602061060c7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006101966105c36101d0565b61016a6105ce6107c6565b6040519485937f04000000000000000000000000000000000000000000000000000000000000008986015260601b166021840152603583019061099b565b01516040519081529081906020820190565b346101cc575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101cc575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc576101c86101bc61016a6101966106ce6107c6565b6040519283917f01000000000000000000000000000000000000000000000000000000000000006020840152602183019061099b565b346101cc5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc5761074861073e6101d0565b60243590336109ad565b602060405160018152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176107c157604052565b610753565b604051905f5f548060011c916001821680156108c7575b60208410811461089a57838652859260208401919081156108635750600114610810575b5061080e92500383610780565b565b5f80805291507f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b84831061084c575061080e9350015f610801565b805482840152869350602090920191600101610838565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682525061080e93151560051b0190505f610801565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b92607f16926107dd565b346101cc575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc576101c86101bc6107c6565b346101cc5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101cc5760206109926109466101d0565b73ffffffffffffffffffffffffffffffffffffffff6109636101f3565b91165f526001835260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54604051908152f35b805191908290602001825e015f815290565b9073ffffffffffffffffffffffffffffffffffffffff8216918215610afa5773ffffffffffffffffffffffffffffffffffffffff8216938415610ace57610ab87fffffffffffffffffffffffffffffffffffffffff000000000000000000000000610a92610ac99461016a7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9784610a436107c6565b916040519687957f0500000000000000000000000000000000000000000000000000000000000000602088015260601b16602186015260601b166035840152866049840152606983019061099b565b7f0000000000000000000000000000000000000000000000000000000000000000610c49565b506040519081529081906020820190565b0390a3565b7fec442f05000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7f96c6fd1e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b3d15610b7e573d9067ffffffffffffffff82116107c15760405191610b7360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610780565b82523d5f602084013e565b606090565b5f918291602082519201905afa610b98610b26565b9015610ba15790565b610bd7906040519182917f0bcb658c000000000000000000000000000000000000000000000000000000008352600483016100c9565b0390fd5b73ffffffffffffffffffffffffffffffffffffffff1690811561030e5773ffffffffffffffffffffffffffffffffffffffff8116156102e257610c46915f52600160205260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b55565b5f91829182602083519301915af1610b98610b2656fea26469706673582212206c349a091a8d116c46a490fccb327923675dd9203b2a952fe99cdb4b058beab664736f6c634300081e0033

precompiles/bank2/ERC20.sol

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
library BankPrecompile {
6+
error BankError(bytes);
7+
8+
enum BankMethod {
9+
NAME,
10+
SYMBOL,
11+
DECIMALS,
12+
TOTAL_SUPPLY,
13+
BALANCE_OF,
14+
TRANSFER_FROM
15+
}
16+
17+
function name(address bank, string memory denom) internal view returns (string memory) {
18+
bytes memory result = _staticcall_bank(bank, abi.encodePacked(uint8(BankMethod.NAME), denom));
19+
return string(result);
20+
}
21+
22+
function symbol(address bank, string memory denom) internal view returns (string memory) {
23+
bytes memory result = _staticcall_bank(bank, abi.encodePacked(uint8(BankMethod.SYMBOL), denom));
24+
return string(result);
25+
}
26+
27+
function decimals(address bank, string memory denom) internal view returns (uint8) {
28+
bytes memory data = _staticcall_bank(bank, abi.encodePacked(uint8(BankMethod.DECIMALS), denom));
29+
30+
uint8 result;
31+
assembly {
32+
result := byte(0, mload(add(data, 0x20)))
33+
}
34+
return result;
35+
}
36+
37+
function totalSupply(address bank, string memory denom) internal view returns (uint256) {
38+
bytes memory data = _staticcall_bank(bank, abi.encodePacked(uint8(BankMethod.TOTAL_SUPPLY), denom));
39+
40+
uint256 result;
41+
assembly {
42+
result := mload(add(data, 0x20))
43+
}
44+
return result;
45+
}
46+
47+
function balanceOf(address bank, address account, string memory denom) internal view returns (uint256) {
48+
bytes memory data = _staticcall_bank(bank, abi.encodePacked(uint8(BankMethod.BALANCE_OF), account, denom));
49+
50+
uint256 result;
51+
assembly {
52+
result := mload(add(data, 0x20))
53+
}
54+
return result;
55+
}
56+
57+
function transferFrom(address bank, address from, address to, uint256 amount, string memory denom) internal returns (bool) {
58+
_call_bank(bank, abi.encodePacked(uint8(BankMethod.TRANSFER_FROM), from, to, amount, denom));
59+
return true;
60+
}
61+
62+
function _staticcall_bank(address bank, bytes memory _calldata) internal view returns (bytes memory) {
63+
(bool success, bytes memory data) = bank.staticcall(_calldata);
64+
if (!success) {
65+
revert BankError(data);
66+
}
67+
68+
return data;
69+
}
70+
71+
function _call_bank(address bank, bytes memory _calldata) internal returns (bytes memory) {
72+
(bool success, bytes memory data) = bank.call(_calldata);
73+
if (!success) {
74+
revert BankError(data);
75+
}
76+
77+
return data;
78+
}
79+
}
80+
81+
interface IERC20 {
82+
event Transfer(address indexed from, address indexed to, uint256 value);
83+
event Approval(address indexed owner, address indexed spender, uint256 value);
84+
function totalSupply() external view returns (uint256);
85+
function balanceOf(address account) external view returns (uint256);
86+
function transfer(address to, uint256 value) external returns (bool);
87+
function allowance(address owner, address spender) external view returns (uint256);
88+
function approve(address spender, uint256 value) external returns (bool);
89+
function transferFrom(address from, address to, uint256 value) external returns (bool);
90+
}
91+
92+
interface IERC20Metadata is IERC20 {
93+
function name() external view returns (string memory);
94+
function symbol() external view returns (string memory);
95+
function decimals() external view returns (uint8);
96+
}
97+
98+
interface IERC20Errors {
99+
error ERC20InvalidSender(address sender);
100+
error ERC20InvalidReceiver(address receiver);
101+
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
102+
error ERC20InvalidApprover(address approver);
103+
error ERC20InvalidSpender(address spender);
104+
}
105+
106+
contract ERC20 is IERC20, IERC20Metadata, IERC20Errors {
107+
using BankPrecompile for address;
108+
109+
string public denom;
110+
mapping(address account => mapping(address spender => uint256)) public allowance;
111+
112+
address public immutable bank;
113+
114+
constructor(string memory denom_, address bank_) {
115+
denom = denom_;
116+
bank = bank_;
117+
}
118+
119+
function name() public view returns (string memory) {
120+
return bank.name(denom);
121+
}
122+
123+
function symbol() public view returns (string memory) {
124+
return bank.symbol(denom);
125+
}
126+
127+
function decimals() public view returns (uint8) {
128+
return bank.decimals(denom);
129+
}
130+
131+
function totalSupply() public view returns (uint256) {
132+
return bank.totalSupply(denom);
133+
}
134+
135+
function balanceOf(address account) public view returns (uint256) {
136+
return bank.balanceOf(account, denom);
137+
}
138+
139+
function transfer(address to, uint256 value) public returns (bool) {
140+
_transfer(msg.sender, to, value);
141+
return true;
142+
}
143+
144+
function approve(address spender, uint256 value) public returns (bool) {
145+
_approve(msg.sender, spender, value);
146+
return true;
147+
}
148+
149+
function transferFrom(address from, address to, uint256 value) public returns (bool) {
150+
address spender = msg.sender;
151+
_spendAllowance(from, spender, value);
152+
_transfer(from, to, value);
153+
return true;
154+
}
155+
156+
function _transfer(address from, address to, uint256 value) internal {
157+
if (from == address(0)) {
158+
revert ERC20InvalidSender(address(0));
159+
}
160+
if (to == address(0)) {
161+
revert ERC20InvalidReceiver(address(0));
162+
}
163+
164+
bank.transferFrom(from, to, value, denom);
165+
emit Transfer(from, to, value);
166+
}
167+
168+
function _approve(address owner, address spender, uint256 value) internal {
169+
_approve(owner, spender, value, true);
170+
}
171+
172+
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
173+
if (owner == address(0)) {
174+
revert ERC20InvalidApprover(address(0));
175+
}
176+
if (spender == address(0)) {
177+
revert ERC20InvalidSpender(address(0));
178+
}
179+
allowance[owner][spender] = value;
180+
if (emitEvent) {
181+
emit Approval(owner, spender, value);
182+
}
183+
}
184+
185+
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
186+
uint256 currentAllowance = allowance[owner][spender];
187+
if (currentAllowance < type(uint256).max) {
188+
if (currentAllowance < value) {
189+
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
190+
}
191+
unchecked {
192+
_approve(owner, spender, currentAllowance - value, false);
193+
}
194+
}
195+
}
196+
}

0 commit comments

Comments
 (0)