-
Notifications
You must be signed in to change notification settings - Fork 17
/
InterchainToken.sol
142 lines (118 loc) · 5.14 KB
/
InterchainToken.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { AddressBytes } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/AddressBytes.sol';
import { IInterchainToken } from '../interfaces/IInterchainToken.sol';
import { InterchainTokenStandard } from './InterchainTokenStandard.sol';
import { ERC20 } from './ERC20.sol';
import { ERC20Permit } from './ERC20Permit.sol';
import { Minter } from '../utils/Minter.sol';
/**
* @title InterchainToken
* @notice This contract implements an interchain token which extends InterchainToken functionality.
* @dev This contract also inherits Minter and Implementation logic.
*/
contract InterchainToken is InterchainTokenStandard, ERC20, ERC20Permit, Minter, IInterchainToken {
using AddressBytes for bytes;
string public name;
string public symbol;
uint8 public decimals;
bytes32 internal tokenId;
address internal immutable interchainTokenService_;
// bytes32(uint256(keccak256('interchain-token-initialized')) - 1);
bytes32 internal constant INITIALIZED_SLOT = 0xc778385ecb3e8cecb82223fa1f343ec6865b2d64c65b0c15c7e8aef225d9e214;
/**
* @notice Constructs the InterchainToken contract.
* @dev Makes the implementation act as if it has been setup already to disallow calls to init() (even though that would not achieve anything really).
*/
constructor(address interchainTokenServiceAddress) {
_initialize();
if (interchainTokenServiceAddress == address(0)) revert InterchainTokenServiceAddressZero();
interchainTokenService_ = interchainTokenServiceAddress;
}
/**
* @notice Returns true if the contract has been setup.
* @return initialized True if the contract has been setup, false otherwise.
*/
function _isInitialized() internal view returns (bool initialized) {
assembly {
initialized := sload(INITIALIZED_SLOT)
}
}
/**
* @notice Sets initialized to true, to allow only a single init.
*/
function _initialize() internal {
assembly {
sstore(INITIALIZED_SLOT, true)
}
}
/**
* @notice Returns the interchain token service
* @return address The interchain token service contract
*/
function interchainTokenService() public view override(InterchainTokenStandard, IInterchainToken) returns (address) {
return interchainTokenService_;
}
/**
* @notice Returns the tokenId for this token.
* @return bytes32 The token manager contract.
*/
function interchainTokenId() public view override(InterchainTokenStandard, IInterchainToken) returns (bytes32) {
return tokenId;
}
/**
* @notice Setup function to initialize contract parameters.
* @param tokenId_ The tokenId of the token.
* @param minter The address of the token minter.
* @param tokenName The name of the token.
* @param tokenSymbol The symbopl of the token.
* @param tokenDecimals The decimals of the token.
*/
function init(bytes32 tokenId_, address minter, string calldata tokenName, string calldata tokenSymbol, uint8 tokenDecimals) external {
if (_isInitialized()) revert AlreadyInitialized();
_initialize();
if (tokenId_ == bytes32(0)) revert TokenIdZero();
if (bytes(tokenName).length == 0) revert TokenNameEmpty();
if (bytes(tokenSymbol).length == 0) revert TokenSymbolEmpty();
name = tokenName;
symbol = tokenSymbol;
decimals = tokenDecimals;
tokenId = tokenId_;
/**
* @dev Set the token service as a minter to allow it to mint and burn tokens.
* Also add the provided address as a minter. If `address(0)` was provided,
* add it as a minter to allow anyone to easily check that no custom minter was set.
*/
_addMinter(interchainTokenService_);
_addMinter(minter);
_setNameHash(tokenName);
}
/**
* @notice Function to mint new tokens.
* @dev Can only be called by the minter address.
* @param account The address that will receive the minted tokens.
* @param amount The amount of tokens to mint.
*/
function mint(address account, uint256 amount) external onlyRole(uint8(Roles.MINTER)) {
_mint(account, amount);
}
/**
* @notice Function to burn tokens.
* @dev Can only be called by the minter address.
* @param account The address that will have its tokens burnt.
* @param amount The amount of tokens to burn.
*/
function burn(address account, uint256 amount) external onlyRole(uint8(Roles.MINTER)) {
_burn(account, amount);
}
/**
* @notice A method to be overwritten that will decrease the allowance of the `spender` from `sender` by `amount`.
* @dev Needs to be overwritten. This provides flexibility for the choice of ERC20 implementation used. Must revert if allowance is not sufficient.
*/
function _spendAllowance(address sender, address spender, uint256 amount) internal override {
uint256 _allowance = allowance[sender][spender];
if (_allowance != UINT256_MAX) {
_approve(sender, spender, _allowance - amount);
}
}
}