Skip to content

Commit 9954e3f

Browse files
Foivosmilapsheth
andauthored
feat: added some info in the tokenManagerProxy, which will cause some gas saving and will allow for a more powerfull design in the future. (#170)
* added some info in the tokenManagerProxy, which will cause some gas saving and will allow for a more powerfull design in the future. * add service approval on appropriate token managers * address comment * refactor imports * update import --------- Co-authored-by: Milap Sheth <[email protected]>
1 parent 9ce5c76 commit 9954e3f

13 files changed

+115
-92
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
/**
6+
* @title IBaseTokenManager
7+
* @notice This contract is defines the base token manager interface implemented by all token managers.
8+
*/
9+
interface IBaseTokenManager {
10+
/**
11+
* @notice A function that returns the token id.
12+
*/
13+
function interchainTokenId() external view returns (bytes32);
14+
15+
/**
16+
* @notice A function that should return the address of the token.
17+
* Must be overridden in the inheriting contract.
18+
* @return address address of the token.
19+
*/
20+
function tokenAddress() external view returns (address);
21+
22+
/**
23+
* @notice A function that should return the implementation type of the token manager.
24+
*/
25+
function implementationType() external pure returns (uint256);
26+
27+
/**
28+
* @notice A function that should return the token address from the init params.
29+
*/
30+
function getTokenAddressFromParams(bytes calldata params) external pure returns (address);
31+
}

contracts/interfaces/ITokenManager.sol

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ pragma solidity ^0.8.0;
44

55
import { IImplementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IImplementation.sol';
66

7-
import { ITokenManagerType } from './ITokenManagerType.sol';
7+
import { IBaseTokenManager } from './IBaseTokenManager.sol';
88
import { IOperatable } from './IOperatable.sol';
99
import { IFlowLimit } from './IFlowLimit.sol';
1010

1111
/**
1212
* @title ITokenManager
1313
* @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one.
1414
*/
15-
interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplementation {
15+
interface ITokenManager is IBaseTokenManager, IOperatable, IFlowLimit, IImplementation {
1616
error TokenLinkerZeroAddress();
1717
error NotService(address caller);
1818
error TakeTokenFailed();
@@ -22,23 +22,6 @@ interface ITokenManager is ITokenManagerType, IOperatable, IFlowLimit, IImplemen
2222
error AlreadyFlowLimiter(address flowLimiter);
2323
error NotFlowLimiter(address flowLimiter);
2424

25-
/**
26-
* @notice A function that returns the token id.
27-
*/
28-
function interchainTokenId() external view returns (bytes32);
29-
30-
/**
31-
* @notice A function that should return the address of the token.
32-
* Must be overridden in the inheriting contract.
33-
* @return address address of the token.
34-
*/
35-
function tokenAddress() external view returns (address);
36-
37-
/**
38-
* @notice A function that should return the implementation type of the token manager.
39-
*/
40-
function implementationType() external pure returns (uint256);
41-
4225
/**
4326
* @notice Calls the service to initiate a cross-chain transfer after taking the appropriate amount of tokens from the user.
4427
* @param destinationChain the name of the chain to send tokens to.

contracts/interfaces/ITokenManagerProxy.sol

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,14 @@ interface ITokenManagerProxy is IProxy {
2222
* @return bytes32 The interchain token ID of the token manager.
2323
*/
2424
function interchainTokenId() external view returns (bytes32);
25+
26+
/**
27+
* @notice Returns token address that this token manager manages.
28+
*/
29+
function tokenAddress() external view returns (address);
30+
31+
/**
32+
* @notice Returns implementation type and token address.
33+
*/
34+
function getImplementationTypeAndTokenAddress() external view returns (uint256, address);
2535
}

contracts/proxies/TokenManagerProxy.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pragma solidity ^0.8.0;
55
import { IProxy } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IProxy.sol';
66
import { BaseProxy } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/BaseProxy.sol';
77

8+
import { IBaseTokenManager } from '../interfaces/IBaseTokenManager.sol';
89
import { ITokenManagerProxy } from '../interfaces/ITokenManagerProxy.sol';
910
import { ITokenManagerImplementation } from '../interfaces/ITokenManagerImplementation.sol';
1011

@@ -19,6 +20,7 @@ contract TokenManagerProxy is BaseProxy, ITokenManagerProxy {
1920
address public immutable interchainTokenService;
2021
uint256 public immutable implementationType;
2122
bytes32 public immutable interchainTokenId;
23+
address public immutable tokenAddress;
2224

2325
/**
2426
* @notice Constructs the TokenManagerProxy contract.
@@ -39,6 +41,8 @@ contract TokenManagerProxy is BaseProxy, ITokenManagerProxy {
3941

4042
(bool success, ) = implementation_.delegatecall(abi.encodeWithSelector(IProxy.setup.selector, params));
4143
if (!success) revert SetupFailed();
44+
45+
tokenAddress = IBaseTokenManager(implementation_).getTokenAddressFromParams(params);
4246
}
4347

4448
/**
@@ -49,6 +53,14 @@ contract TokenManagerProxy is BaseProxy, ITokenManagerProxy {
4953
return CONTRACT_ID;
5054
}
5155

56+
/**
57+
* @notice Returns implementation type and token address.
58+
*/
59+
function getImplementationTypeAndTokenAddress() external view returns (uint256 implementationType_, address tokenAddress_) {
60+
implementationType_ = implementationType;
61+
tokenAddress_ = tokenAddress;
62+
}
63+
5264
/**
5365
* @notice Returns the address of the current implementation.
5466
* @return implementation_ The address of the current implementation.

contracts/test/HardCodedConstantsTest.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ contract TestTokenManager is TokenManagerLiquidityPool {
1414
string public constant NAME = 'TestTokenManager';
1515

1616
constructor(address interchainTokenService_) TokenManagerLiquidityPool(interchainTokenService_) {
17-
if (TOKEN_ADDRESS_SLOT != uint256(keccak256('token-address')) - 1) revert Invalid();
1817
if (LIQUIDITY_POOL_SLOT != uint256(keccak256('liquidity-pool-slot')) - 1) revert Invalid();
1918
}
2019
}

contracts/token-manager/TokenManager.sol

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { IImplementation } from '@axelar-network/axelar-gmp-sdk-solidity/contrac
77
import { Implementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Implementation.sol';
88

99
import { ITokenManager } from '../interfaces/ITokenManager.sol';
10+
import { ITokenManagerType } from '../interfaces/ITokenManagerType.sol';
1011
import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol';
1112

1213
import { Operatable } from '../utils/Operatable.sol';
@@ -16,16 +17,13 @@ import { FlowLimit } from '../utils/FlowLimit.sol';
1617
* @title The main functionality of TokenManagers.
1718
* @notice This contract is responsible for handling tokens before initiating a cross chain token transfer, or after receiving one.
1819
*/
19-
abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implementation {
20+
abstract contract TokenManager is ITokenManager, ITokenManagerType, Operatable, FlowLimit, Implementation {
2021
using AddressBytes for bytes;
2122

2223
IInterchainTokenService public immutable interchainTokenService;
2324

2425
bytes32 private constant CONTRACT_ID = keccak256('token-manager');
2526

26-
// uint256(keccak256('token-address')) - 1
27-
uint256 internal constant TOKEN_ADDRESS_SLOT = 0xc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42ba;
28-
2927
/**
3028
* @notice Constructs the TokenManager contract.
3129
* @param interchainTokenService_ The address of the interchain token service
@@ -48,7 +46,7 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen
4846
* @dev A modifier that allows only the token to execute the function.
4947
*/
5048
modifier onlyToken() {
51-
if (msg.sender != tokenAddress()) revert NotToken(msg.sender);
49+
if (msg.sender != this.tokenAddress()) revert NotToken(msg.sender);
5250
_;
5351
}
5452

@@ -60,13 +58,12 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen
6058
}
6159

6260
/**
63-
* @dev Reads the stored token address from the predetermined storage slot
61+
* @dev Reads the token address from the proxy
6462
* @return tokenAddress_ The address of the token
6563
*/
66-
function tokenAddress() public view virtual returns (address tokenAddress_) {
67-
assembly {
68-
tokenAddress_ := sload(TOKEN_ADDRESS_SLOT)
69-
}
64+
function tokenAddress() external view virtual returns (address tokenAddress_) {
65+
// Ask the proxy what the token address is.
66+
tokenAddress_ = this.tokenAddress();
7067
}
7168

7269
/**
@@ -78,6 +75,13 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen
7875
return this.interchainTokenId();
7976
}
8077

78+
/**
79+
* @notice A function that should return the token address from the setup params.
80+
*/
81+
function getTokenAddressFromParams(bytes calldata params) external pure returns (address tokenAddress_) {
82+
(, tokenAddress_) = abi.decode(params, (uint256, address));
83+
}
84+
8185
/**
8286
* @dev This function should only be called by the proxy, and only once from the proxy constructor
8387
* @param params the parameters to be used to initialize the TokenManager. The exact format depends
@@ -251,16 +255,6 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen
251255
_setFlowLimit(flowLimit_, interchainTokenId());
252256
}
253257

254-
/**
255-
* @dev Stores the token address in the predetermined storage slot
256-
* @param tokenAddress_ The address of the token to store
257-
*/
258-
function _setTokenAddress(address tokenAddress_) internal {
259-
assembly {
260-
sstore(TOKEN_ADDRESS_SLOT, tokenAddress_)
261-
}
262-
}
263-
264258
/**
265259
* @notice Transfers tokens from a specific address to this contract.
266260
* Must be overridden in the inheriting contract.
@@ -284,5 +278,5 @@ abstract contract TokenManager is ITokenManager, Operatable, FlowLimit, Implemen
284278
* Must be overridden in the inheriting contract.
285279
* @param params The setup parameters
286280
*/
287-
function _setup(bytes calldata params) internal virtual;
281+
function _setup(bytes calldata params) internal virtual {}
288282
}

contracts/token-manager/TokenManagerLiquidityPool.sol

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pragma solidity ^0.8.0;
44

55
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
6-
import { SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
6+
import { SafeTokenTransferFrom, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
77
import { ReentrancyGuard } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/ReentrancyGuard.sol';
88

99
import { ITokenManagerLiquidityPool } from '../interfaces/ITokenManagerLiquidityPool.sol';
@@ -18,6 +18,7 @@ import { TokenManager } from './TokenManager.sol';
1818
*/
1919
contract TokenManagerLiquidityPool is TokenManager, ReentrancyGuard, ITokenManagerLiquidityPool {
2020
using SafeTokenTransferFrom for IERC20;
21+
using SafeTokenCall for IERC20;
2122

2223
error NotSupported();
2324

@@ -41,9 +42,10 @@ contract TokenManagerLiquidityPool is TokenManager, ReentrancyGuard, ITokenManag
4142
*/
4243
function _setup(bytes calldata params_) internal override {
4344
// The first argument is reserved for the operator.
44-
(, address tokenAddress_, address liquidityPool_) = abi.decode(params_, (bytes, address, address));
45-
_setTokenAddress(tokenAddress_);
45+
(, address tokenAddress_, address liquidityPool_) = abi.decode(params_, (uint256, address, address));
4646
_setLiquidityPool(liquidityPool_);
47+
48+
IERC20(tokenAddress_).safeCall(abi.encodeWithSelector(IERC20.approve.selector, interchainTokenService, type(uint256).max));
4749
}
4850

4951
/**
@@ -81,7 +83,7 @@ contract TokenManagerLiquidityPool is TokenManager, ReentrancyGuard, ITokenManag
8183
* @return uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens.
8284
*/
8385
function _takeToken(address from, uint256 amount) internal override noReEntrancy returns (uint256) {
84-
IERC20 token = IERC20(tokenAddress());
86+
IERC20 token = IERC20(this.tokenAddress());
8587
address liquidityPool_ = liquidityPool();
8688
uint256 balance = token.balanceOf(liquidityPool_);
8789

@@ -101,7 +103,7 @@ contract TokenManagerLiquidityPool is TokenManager, ReentrancyGuard, ITokenManag
101103
* @return uint The actual amount of tokens transferred
102104
*/
103105
function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) {
104-
IERC20 token = IERC20(tokenAddress());
106+
IERC20 token = IERC20(this.tokenAddress());
105107
uint256 balance = token.balanceOf(to);
106108

107109
// slither-disable-next-line arbitrary-send-erc20

contracts/token-manager/TokenManagerLockUnlock.sol

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pragma solidity ^0.8.0;
44

55
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
6-
import { SafeTokenTransfer, SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
6+
import { SafeTokenTransfer, SafeTokenTransferFrom, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
77

88
import { ITokenManagerLockUnlock } from '..//interfaces/ITokenManagerLockUnlock.sol';
99
import { TokenManager } from './TokenManager.sol';
@@ -17,6 +17,7 @@ import { TokenManager } from './TokenManager.sol';
1717
contract TokenManagerLockUnlock is TokenManager, ITokenManagerLockUnlock {
1818
using SafeTokenTransfer for IERC20;
1919
using SafeTokenTransferFrom for IERC20;
20+
using SafeTokenCall for IERC20;
2021

2122
/**
2223
* @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor
@@ -30,13 +31,14 @@ contract TokenManagerLockUnlock is TokenManager, ITokenManagerLockUnlock {
3031
}
3132

3233
/**
33-
* @dev Sets up the token address.
34-
* @param params_ The setup parameters in bytes. Should be encoded with the token address.
34+
* @dev Sets up the token address and liquidity pool address.
35+
* @param params_ The setup parameters in bytes. Should be encoded with the token address and the liquidity pool address.
3536
*/
3637
function _setup(bytes calldata params_) internal override {
3738
// The first argument is reserved for the operator.
38-
(, address tokenAddress_) = abi.decode(params_, (bytes, address));
39-
_setTokenAddress(tokenAddress_);
39+
(, address tokenAddress_) = abi.decode(params_, (uint256, address));
40+
41+
IERC20(tokenAddress_).safeCall(abi.encodeWithSelector(IERC20.approve.selector, interchainTokenService, type(uint256).max));
4042
}
4143

4244
/**
@@ -46,7 +48,7 @@ contract TokenManagerLockUnlock is TokenManager, ITokenManagerLockUnlock {
4648
* @return uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens.
4749
*/
4850
function _takeToken(address from, uint256 amount) internal override returns (uint256) {
49-
IERC20 token = IERC20(tokenAddress());
51+
IERC20 token = IERC20(this.tokenAddress());
5052

5153
token.safeTransferFrom(from, address(this), amount);
5254

@@ -60,7 +62,7 @@ contract TokenManagerLockUnlock is TokenManager, ITokenManagerLockUnlock {
6062
* @return uint The actual amount of tokens transferred
6163
*/
6264
function _giveToken(address to, uint256 amount) internal override returns (uint256) {
63-
IERC20 token = IERC20(tokenAddress());
65+
IERC20 token = IERC20(this.tokenAddress());
6466

6567
token.safeTransfer(to, amount);
6668

contracts/token-manager/TokenManagerLockUnlockFee.sol

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pragma solidity ^0.8.0;
44

55
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
6-
import { SafeTokenTransferFrom, SafeTokenTransfer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
6+
import { SafeTokenTransferFrom, SafeTokenTransfer, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
77
import { ReentrancyGuard } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/ReentrancyGuard.sol';
88

99
import { ITokenManagerLockUnlock } from '../interfaces/ITokenManagerLockUnlock.sol';
@@ -18,6 +18,7 @@ import { TokenManager } from './TokenManager.sol';
1818
contract TokenManagerLockUnlockFee is TokenManager, ReentrancyGuard, ITokenManagerLockUnlock {
1919
using SafeTokenTransfer for IERC20;
2020
using SafeTokenTransferFrom for IERC20;
21+
using SafeTokenCall for IERC20;
2122

2223
/**
2324
* @dev Constructs an instance of TokenManagerLockUnlock. Calls the constructor
@@ -31,13 +32,14 @@ contract TokenManagerLockUnlockFee is TokenManager, ReentrancyGuard, ITokenManag
3132
}
3233

3334
/**
34-
* @dev Sets up the token address.
35-
* @param params_ The setup parameters in bytes. Should be encoded with the token address.
35+
* @dev Sets up the token address and liquidity pool address.
36+
* @param params_ The setup parameters in bytes. Should be encoded with the token address and the liquidity pool address.
3637
*/
3738
function _setup(bytes calldata params_) internal override {
3839
// The first argument is reserved for the operator.
39-
(, address tokenAddress_) = abi.decode(params_, (bytes, address));
40-
_setTokenAddress(tokenAddress_);
40+
(, address tokenAddress_) = abi.decode(params_, (uint256, address));
41+
42+
IERC20(tokenAddress_).safeCall(abi.encodeWithSelector(IERC20.approve.selector, interchainTokenService, type(uint256).max));
4143
}
4244

4345
/**
@@ -47,7 +49,7 @@ contract TokenManagerLockUnlockFee is TokenManager, ReentrancyGuard, ITokenManag
4749
* @return uint The actual amount of tokens transferred. This allows support for fee-on-transfer tokens.
4850
*/
4951
function _takeToken(address from, uint256 amount) internal override noReEntrancy returns (uint256) {
50-
IERC20 token = IERC20(tokenAddress());
52+
IERC20 token = IERC20(this.tokenAddress());
5153
uint256 balanceBefore = token.balanceOf(address(this));
5254

5355
token.safeTransferFrom(from, address(this), amount);
@@ -67,7 +69,7 @@ contract TokenManagerLockUnlockFee is TokenManager, ReentrancyGuard, ITokenManag
6769
* @return uint The actual amount of tokens transferred
6870
*/
6971
function _giveToken(address to, uint256 amount) internal override noReEntrancy returns (uint256) {
70-
IERC20 token = IERC20(tokenAddress());
72+
IERC20 token = IERC20(this.tokenAddress());
7173
uint256 balanceBefore = token.balanceOf(to);
7274

7375
token.safeTransfer(to, amount);

0 commit comments

Comments
 (0)