1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^ 0.8.0 ;
3
+
4
+ import "@openzeppelin/contracts/token/ERC20/ERC20.sol " ;
5
+ import "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
6
+ import "@openzeppelin/contracts/utils/Strings.sol " ;
7
+ import {IWasmd} from "./precompiles/IWasmd.sol " ;
8
+ import {IJson} from "./precompiles/IJson.sol " ;
9
+ import {IAddr} from "./precompiles/IAddr.sol " ;
10
+
11
+ contract CW20ERC20Wrapper is ERC20 {
12
+
13
+ address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002 ;
14
+ address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003 ;
15
+ address constant ADDR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001004 ;
16
+
17
+ string public Cw20Address;
18
+ IWasmd public WasmdPrecompile;
19
+ IJson public JsonPrecompile;
20
+ IAddr public AddrPrecompile;
21
+
22
+ constructor (string memory Cw20Address_ , string memory name_ , string memory symbol_ ) ERC20 (name_, symbol_) {
23
+ WasmdPrecompile = IWasmd (WASMD_PRECOMPILE_ADDRESS);
24
+ JsonPrecompile = IJson (JSON_PRECOMPILE_ADDRESS);
25
+ AddrPrecompile = IAddr (ADDR_PRECOMPILE_ADDRESS);
26
+ Cw20Address = Cw20Address_;
27
+ }
28
+
29
+ // Queries
30
+ function decimals () public view override returns (uint8 ) {
31
+ string memory req = _curlyBrace (_formatPayload ("token_info " , "{} " ));
32
+ bytes memory response = WasmdPrecompile.query (Cw20Address, bytes (req));
33
+ return uint8 (JsonPrecompile.extractAsUint256 (response, "decimals " ));
34
+ }
35
+
36
+ function balanceOf (address owner ) public view override returns (uint256 ) {
37
+ require (owner != address (0 ), "ERC20: balance query for the zero address " );
38
+ string memory ownerAddr = _formatPayload ("address " , _doubleQuotes (AddrPrecompile.getSeiAddr (owner)));
39
+ string memory req = _curlyBrace (_formatPayload ("balance " , _curlyBrace (ownerAddr)));
40
+ bytes memory response = WasmdPrecompile.query (Cw20Address, bytes (req));
41
+ return JsonPrecompile.extractAsUint256 (response, "balance " );
42
+ }
43
+
44
+ function totalSupply () public view override returns (uint256 ) {
45
+ string memory req = _curlyBrace (_formatPayload ("token_info " , "{} " ));
46
+ bytes memory response = WasmdPrecompile.query (Cw20Address, bytes (req));
47
+ return JsonPrecompile.extractAsUint256 (response, "total_supply " );
48
+ }
49
+
50
+ function allowance (address owner , address spender ) public view override returns (uint256 ) {
51
+ string memory o = _formatPayload ("owner " , _doubleQuotes (AddrPrecompile.getSeiAddr (owner)));
52
+ string memory s = _formatPayload ("spender " , _doubleQuotes (AddrPrecompile.getSeiAddr (spender)));
53
+ string memory req = _curlyBrace (_formatPayload ("allowance " , _curlyBrace (_join (o, s, ", " ))));
54
+ bytes memory response = WasmdPrecompile.query (Cw20Address, bytes (req));
55
+ return JsonPrecompile.extractAsUint256 (response, "allowance " );
56
+ }
57
+
58
+ // Transactions
59
+ function approve (address spender , uint256 amount ) public override returns (bool ) {
60
+ uint256 currentAllowance = allowance (msg .sender , spender);
61
+ if (currentAllowance > amount) {
62
+ string memory spenderAddr = _formatPayload ("spender " , _doubleQuotes (AddrPrecompile.getSeiAddr (spender)));
63
+ string memory amt = _formatPayload ("amount " , _doubleQuotes (Strings.toString (currentAllowance - amount)));
64
+ string memory req = _curlyBrace (_formatPayload ("decrease_allowance " , _curlyBrace (_join (spenderAddr, amt, ", " ))));
65
+ _execute (bytes (req));
66
+ } else if (currentAllowance < amount) {
67
+ string memory spenderAddr = _formatPayload ("spender " , _doubleQuotes (AddrPrecompile.getSeiAddr (spender)));
68
+ string memory amt = _formatPayload ("amount " , _doubleQuotes (Strings.toString (amount - currentAllowance)));
69
+ string memory req = _curlyBrace (_formatPayload ("increase_allowance " , _curlyBrace (_join (spenderAddr, amt, ", " ))));
70
+ _execute (bytes (req));
71
+ }
72
+ emit Approval (msg .sender , spender, amount);
73
+ return true ;
74
+ }
75
+
76
+ function transfer (address to , uint256 amount ) public override returns (bool ) {
77
+ require (to != address (0 ), "ERC20: transfer to the zero address " );
78
+ string memory recipient = _formatPayload ("recipient " , _doubleQuotes (AddrPrecompile.getSeiAddr (to)));
79
+ string memory amt = _formatPayload ("amount " , _doubleQuotes (Strings.toString (amount)));
80
+ string memory req = _curlyBrace (_formatPayload ("transfer " , _curlyBrace (_join (recipient, amt, ", " ))));
81
+ _execute (bytes (req));
82
+ emit Transfer (msg .sender , to, amount);
83
+ return true ;
84
+ }
85
+
86
+ function transferFrom (address from , address to , uint256 amount ) public override returns (bool ) {
87
+ require (to != address (0 ), "ERC20: transfer to the zero address " );
88
+ string memory sender = _formatPayload ("owner " , _doubleQuotes (AddrPrecompile.getSeiAddr (from)));
89
+ string memory recipient = _formatPayload ("recipient " , _doubleQuotes (AddrPrecompile.getSeiAddr (to)));
90
+ string memory amt = _formatPayload ("amount " , _doubleQuotes (Strings.toString (amount)));
91
+ string memory req = _curlyBrace (_formatPayload ("transfer_from " , _curlyBrace (_join (_join (sender, recipient, ", " ), amt, ", " ))));
92
+ _execute (bytes (req));
93
+ emit Transfer (from, to, amount);
94
+ return true ;
95
+ }
96
+
97
+ function _execute (bytes memory req ) internal returns (bytes memory ) {
98
+ (bool success , bytes memory ret ) = WASMD_PRECOMPILE_ADDRESS.delegatecall (
99
+ abi.encodeWithSignature (
100
+ "execute(string,bytes,bytes) " ,
101
+ Cw20Address,
102
+ bytes (req),
103
+ bytes ("[] " )
104
+ )
105
+ );
106
+ require (success, "CosmWasm execute failed " );
107
+ return ret;
108
+ }
109
+
110
+ function _formatPayload (string memory key , string memory value ) internal pure returns (string memory ) {
111
+ return _join (_doubleQuotes (key), value, ": " );
112
+ }
113
+
114
+ function _curlyBrace (string memory s ) internal pure returns (string memory ) {
115
+ return string .concat ("{ " , string .concat (s, "} " ));
116
+ }
117
+
118
+ function _doubleQuotes (string memory s ) internal pure returns (string memory ) {
119
+ return string .concat ("\" " , string .concat (s, "\" " ));
120
+ }
121
+
122
+ function _join (string memory a , string memory b , string memory separator ) internal pure returns (string memory ) {
123
+ return string .concat (a, string .concat (separator, b));
124
+ }
125
+ }
0 commit comments