Quai Network Logo

Token Deployer

Easily deploy your ERC20 token on Quai Network.

Enter the name of your token.

Enter your token ticker.

Set the intitial supply of your token.

The ERC20 Contract

The Quai Token deployer is configured to deploy the base implementation of Open Zeppelin's ERC20 standard expanded with a Ownable modifier contract. Deploying the contract will create a new single-chain token with the specified name, symbol, and supply. You, as the owner, will be minted the entirety of the token supply, and will be able to mint new tokens and transfer ownership of the token contract.

While the contract below is useful for simple deployments, it lacks customizability. If your token requires more advanced features such as custom distribution, consider writing your own contract and deploying it via Hardhat.

erc20.sol

1
// SPDX-License-Identifier: MIT
2
3
pragma solidity 0.8.17;
4
5
import "./Address.sol";
6
import "./IERC20.sol";
7
import "./IERC20Metadata.sol";
8
import "./EIP712.sol";
9
import "./Nonces.sol";
10
import "./IERC20Permit.sol";
11
import "./ECDSA.sol";
12
13
contract ERC20 is IERC20, IERC20Metadata, IERC20Permit, EIP712, Nonces {
14
using Address for address;
15
16
bytes32 private constant PERMIT_TYPEHASH =
17
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
18
19
/**
20
* @dev Permit deadline has expired.
21
*/
22
error ERC2612ExpiredSignature(uint256 deadline);
23
24
/**
25
* @dev Mismatched signature.
26
*/
27
error ERC2612InvalidSigner(address signer, address owner);
28
29
mapping(address => uint256) private _balances;
30
mapping(address => mapping(address => uint256)) private _allowances;
31
uint256 private _totalSupply;
32
string private _name;
33
string private _symbol;
34
35
constructor(
36
string memory name_,
37
string memory symbol_,
38
uint256 totalSupply_
39
) EIP712(name_, "1") {
40
_name = name_;
41
_symbol = symbol_;
42
_mint(msg.sender, totalSupply_);
43
}
44
45
function name() public view virtual override returns (string memory) {
46
return _name;
47
}
48
49
function symbol() public view virtual override returns (string memory) {
50
return _symbol;
51
}
52
53
function decimals() public view virtual override returns (uint8) {
54
return 18;
55
}
56
57
function totalSupply() public view virtual override returns (uint256) {
58
return _totalSupply;
59
}
60
61
function balanceOf(
62
address account
63
) public view virtual override returns (uint256) {
64
return _balances[account];
65
}
66
67
function transferFrom(
68
address sender,
69
address recipient,
70
uint256 amount
71
) public virtual override returns (bool) {
72
_transfer(sender, recipient, amount);
73
74
uint256 currentAllowance = _allowances[sender][msg.sender];
75
require(
76
currentAllowance >= amount,
77
"ERC20: transfer amount exceeds allowance"
78
);
79
unchecked {
80
_approve(sender, msg.sender, currentAllowance - amount);
81
}
82
83
return true;
84
}
85
86
function transfer(
87
address recipient,
88
uint256 amount
89
) public virtual override returns (bool) {
90
_transfer(msg.sender, recipient, amount);
91
return true;
92
}
93
94
function allowance(
95
address owner,
96
address spender
97
) public view virtual override returns (uint256) {
98
return _allowances[owner][spender];
99
}
100
101
function approve(
102
address spender,
103
uint256 amount
104
) public virtual override returns (bool) {
105
_approve(msg.sender, spender, amount);
106
return true;
107
}
108
109
function decreaseAllowance(
110
address spender,
111
uint256 subtractedValue
112
) public virtual returns (bool) {
113
uint256 currentAllowance = _allowances[msg.sender][spender];
114
require(
115
currentAllowance >= subtractedValue,
116
"ERC20: decreased allowance below zero"
117
);
118
unchecked {
119
_approve(msg.sender, spender, currentAllowance - subtractedValue);
120
}
121
122
return true;
123
}
124
125
function increaseAllowance(
126
address spender,
127
uint256 addedValue
128
) public virtual returns (bool) {
129
_approve(
130
msg.sender,
131
spender,
132
_allowances[msg.sender][spender] + addedValue
133
);
134
return true;
135
}
136
137
function _transfer(
138
address sender,
139
address recipient,
140
uint256 amount
141
) internal virtual {
142
require(sender != address(0), "ERC20: transfer from the zero address");
143
require(recipient != address(0), "ERC20: transfer to the zero address");
144
145
uint256 senderBalance = _balances[sender];
146
require(
147
senderBalance >= amount,
148
"ERC20: transfer amount exceeds balance"
149
);
150
unchecked {
151
_balances[sender] = senderBalance - amount;
152
}
153
_balances[recipient] += amount;
154
155
emit Transfer(sender, recipient, amount);
156
}
157
158
function _mint(address account, uint256 amount) internal virtual {
159
require(account != address(0), "ERC20: mint to the zero address");
160
161
_totalSupply += amount;
162
_balances[account] += amount;
163
emit Transfer(address(0), account, amount);
164
}
165
166
function _burn(address account, uint256 amount) internal virtual {
167
require(account != address(0), "ERC20: burn from the zero address");
168
169
uint256 accountBalance = _balances[account];
170
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
171
unchecked {
172
_balances[account] = accountBalance - amount;
173
}
174
_totalSupply -= amount;
175
176
emit Transfer(account, address(0), amount);
177
}
178
179
function _approve(
180
address owner,
181
address spender,
182
uint256 amount
183
) internal virtual {
184
require(owner != address(0), "ERC20: approve from the zero address");
185
require(spender != address(0), "ERC20: approve to the zero address");
186
187
_allowances[owner][spender] = amount;
188
emit Approval(owner, spender, amount);
189
}
190
191
/**
192
* @inheritdoc IERC20Permit
193
*/
194
function permit(
195
address owner,
196
address spender,
197
uint256 value,
198
uint256 deadline,
199
uint8 v,
200
bytes32 r,
201
bytes32 s
202
) public virtual {
203
if (block.timestamp > deadline) {
204
revert ERC2612ExpiredSignature(deadline);
205
}
206
207
bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
208
209
bytes32 hash = _hashTypedDataV4(structHash);
210
211
address signer = ECDSA.recover(hash, v, r, s);
212
if (signer != owner) {
213
revert ERC2612InvalidSigner(signer, owner);
214
}
215
216
_approve(owner, spender, value);
217
}
218
219
/**
220
* @inheritdoc IERC20Permit
221
*/
222
function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
223
return super.nonces(owner);
224
}
225
226
/**
227
* @inheritdoc IERC20Permit
228
*/
229
// solhint-disable-next-line func-name-mixedcase
230
function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
231
return _domainSeparatorV4();
232
}
233
}