-
Notifications
You must be signed in to change notification settings - Fork 1
/
AssetFacet.sol
204 lines (166 loc) · 7.67 KB
/
AssetFacet.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// SPDX-License-Identifier: MIT
pragma solidity 0.8.14;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {BaseConnextFacet} from "./BaseConnextFacet.sol";
import {ConnextMessage} from "../libraries/ConnextMessage.sol";
import {IStableSwap} from "../interfaces/IStableSwap.sol";
import {IWrapped} from "../interfaces/IWrapped.sol";
import {ITokenRegistry} from "../interfaces/ITokenRegistry.sol";
contract AssetFacet is BaseConnextFacet {
// ========== Custom Errors ===========
error AssetFacet__setWrapper_invalidWrapper();
error AssetFacet__setTokenRegistry_invalidTokenRegistry();
error AssetFacet__addAssetId_alreadyAdded();
error AssetFacet__removeAssetId_notAdded();
// ============ Events ============
/**
* @notice Emitted when the wrapper variable is updated
* @param oldWrapper - The wrapper old value
* @param newWrapper - The wrapper new value
* @param caller - The account that called the function
*/
event WrapperUpdated(address oldWrapper, address newWrapper, address caller);
/**
* @notice Emitted when the tokenRegistry variable is updated
* @param oldTokenRegistry - The tokenRegistry old value
* @param newTokenRegistry - The tokenRegistry new value
* @param caller - The account that called the function
*/
event TokenRegistryUpdated(address oldTokenRegistry, address newTokenRegistry, address caller);
/**
* @notice Emitted when a new stable-swap AMM is added for the local <> adopted token
* @param canonicalId - The canonical identifier of the token the local <> adopted AMM is for
* @param domain - The domain of the canonical token for the local <> adopted amm
* @param swapPool - The address of the AMM
* @param caller - The account that called the function
*/
event StableSwapAdded(bytes32 canonicalId, uint32 domain, address swapPool, address caller);
/**
* @notice Emitted when a new asset is added
* @param canonicalId - The canonical identifier of the token the local <> adopted AMM is for
* @param domain - The domain of the canonical token for the local <> adopted amm
* @param adoptedAsset - The address of the adopted (user-expected) asset
* @param supportedAsset - The address of the whitelisted asset. If the native asset is to be whitelisted,
* the address of the wrapped version will be stored
* @param caller - The account that called the function
*/
event AssetAdded(bytes32 canonicalId, uint32 domain, address adoptedAsset, address supportedAsset, address caller);
/**
* @notice Emitted when an asset is removed from whitelists
* @param canonicalId - The canonical identifier of the token removed
* @param caller - The account that called the function
*/
event AssetRemoved(bytes32 canonicalId, address caller);
// ============ Getters ============
function canonicalToAdopted(bytes32 _canonicalId) public view returns (address) {
return s.canonicalToAdopted[_canonicalId];
}
function adoptedToCanonical(address _adopted) public view returns (ConnextMessage.TokenId memory) {
ConnextMessage.TokenId memory canonical = ConnextMessage.TokenId(
s.adoptedToCanonical[_adopted].domain,
s.adoptedToCanonical[_adopted].id
);
return canonical;
}
function approvedAssets(bytes32 _asset) public view returns (bool) {
return s.approvedAssets[_asset];
}
function adoptedToLocalPools(bytes32 _adopted) public view returns (IStableSwap) {
return s.adoptedToLocalPools[_adopted];
}
function wrapper() public view returns (IWrapped) {
return s.wrapper;
}
function tokenRegistry() public view returns (ITokenRegistry) {
return s.tokenRegistry;
}
// ============ Admin functions ============
/**
* @notice Updates the native-asset wrapper interface
* @param _wrapper The address of the new wrapper
*/
function setWrapper(address _wrapper) external onlyOwner {
address old = address(s.wrapper);
if (old == _wrapper || !Address.isContract(_wrapper)) revert AssetFacet__setWrapper_invalidWrapper();
s.wrapper = IWrapped(_wrapper);
emit WrapperUpdated(old, _wrapper, msg.sender);
}
/**
* @notice Updates the token registry
* @param _tokenRegistry The new token registry address
*/
function setTokenRegistry(address _tokenRegistry) external onlyOwner {
address old = address(s.tokenRegistry);
if (old == _tokenRegistry || !Address.isContract(_tokenRegistry))
revert AssetFacet__setTokenRegistry_invalidTokenRegistry();
s.tokenRegistry = ITokenRegistry(_tokenRegistry);
emit TokenRegistryUpdated(old, _tokenRegistry, msg.sender);
}
/**
* @notice Used to add supported assets. This is an admin only function
* @dev When whitelisting the canonical asset, all representational assets would be
* whitelisted as well. In the event you have a different adopted asset (i.e. PoS USDC
* on polygon), you should *not* whitelist the adopted asset. The stable swap pool
* address used should allow you to swap between the local <> adopted asset
* @param _canonical - The canonical asset to add by id and domain. All representations
* will be whitelisted as well
* @param _adoptedAssetId - The used asset id for this domain (i.e. PoS USDC for
* polygon)
*/
function setupAsset(
ConnextMessage.TokenId calldata _canonical,
address _adoptedAssetId,
address _stableSwapPool
) external onlyOwner {
// Sanity check: needs approval
if (s.approvedAssets[_canonical.id]) revert AssetFacet__addAssetId_alreadyAdded();
// Update approved assets mapping
s.approvedAssets[_canonical.id] = true;
address supported = _adoptedAssetId == address(0) ? address(s.wrapper) : _adoptedAssetId;
// Update the adopted mapping
s.adoptedToCanonical[supported].domain = _canonical.domain;
s.adoptedToCanonical[supported].id = _canonical.id;
// Update the canonical mapping
s.canonicalToAdopted[_canonical.id] = supported;
// Emit event
emit AssetAdded(_canonical.id, _canonical.domain, _adoptedAssetId, supported, msg.sender);
// Add the swap pool
_addStableSwapPool(_canonical, _stableSwapPool);
}
/**
* @notice Adds a stable swap pool for the local <> adopted asset.
*/
function addStableSwapPool(ConnextMessage.TokenId calldata _canonical, address _stableSwapPool) external onlyOwner {
_addStableSwapPool(_canonical, _stableSwapPool);
}
/**
* @notice Used to remove assets from the whitelist
* @param _canonicalId - Token id to remove
* @param _adoptedAssetId - Corresponding adopted asset to remove
*/
function removeAssetId(bytes32 _canonicalId, address _adoptedAssetId) external onlyOwner {
// Sanity check: already approval
if (!s.approvedAssets[_canonicalId]) revert AssetFacet__removeAssetId_notAdded();
// Delete from approved assets mapping
delete s.approvedAssets[_canonicalId];
// Delete from pools
delete s.adoptedToLocalPools[_canonicalId];
// Delete from adopted mapping
delete s.adoptedToCanonical[_adoptedAssetId == address(0) ? address(s.wrapper) : _adoptedAssetId];
// Delete from canonical mapping
delete s.canonicalToAdopted[_canonicalId];
// Emit event
emit AssetRemoved(_canonicalId, msg.sender);
}
// ============ Private Functions ============
/**
* @notice Used to add an AMM for adopted <> local assets
* @param _canonical - The canonical TokenId to add (domain and id)
* @param _stableSwap - The address of the amm to add
*/
function _addStableSwapPool(ConnextMessage.TokenId calldata _canonical, address _stableSwap) internal {
// Update the pool mapping
s.adoptedToLocalPools[_canonical.id] = IStableSwap(_stableSwap);
emit StableSwapAdded(_canonical.id, _canonical.domain, _stableSwap, msg.sender);
}
}