Skip to content

Commit

Permalink
(feat) Add a scale factor to the V4 token maanager
Browse files Browse the repository at this point in the history
  • Loading branch information
rrw-zilliqa committed Jan 7, 2025
1 parent bcbfac6 commit bc83607
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,37 @@ import {ITokenManagerEvents, ITokenManagerStructs} from "contracts/periphery/Tok
import {TokenManagerFees, ITokenManagerFees} from "contracts/periphery/TokenManagerV2/TokenManagerFees.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";

interface ITokenManagerV4Structs {
struct ScaledRemoteToken {
address token;
address tokenManager;
uint chainId;
int8 scale;
}
}

interface ITokenManagerV4Events {
event TokenScaleChanged (
address indexed token,
uint remoteChainId,
int8 remoteScale
);
}

interface ITokenManager is
ITokenManagerEvents,
ITokenManagerStructs,
ITokenManagerFees
ITokenManagerFees,
ITokenManagerV4Structs,
ITokenManagerV4Events
{
error InvalidSourceChainId();
error InvalidTokenManager();
error NotGateway();
error InvalidTokenRouting();
// the amount of local tokens we tried to send, the nearest scaled amount we could recieve on the target chain, and
// the amount of local tokens that would correspond to.
error InvalidTokenAmount(uint256 sent, uint256 adjusted, uint256 reconstructed);

function getGateway() external view returns (address);

Expand Down Expand Up @@ -73,6 +95,7 @@ abstract contract TokenManagerUpgradeableV4 is
bytes32 private constant Token_Manager_Storage_Location =
0x4a6c2e6a7e6518c249bdcd1d934ea16ea5325bbae105af814eb678f5f49f3400;


function _getTokenManagerStorage()
private
pure
Expand All @@ -83,6 +106,28 @@ abstract contract TokenManagerUpgradeableV4 is
}
}

struct TokenManagerV4Storage {
// This stores the scale for remote tokens, as remote_token.decimals-local_token.decimals.
// So, when sending a token with a +ve scale, we shift left.
// When sending a token with a -ve scale, we shift right.
// When receiving a token, we do nothing.
// This allows us to validate that the tokens can be exactly converted to the remote
// and revert the sending txn if not.
mapping(address => mapping(uint => int8)) scaleForRemoteTokens;
}

// keccack256(abi.encode(uint256(keccak256("zilliqa.storage.TokenManagerV4"))-1))& ~bytes32(uint256(0xff))
bytes32 private constant Token_ManagerV4_Storage_Location =
0xe8b1c929e9ac4c16aaeb9d6494126adb9c7e3b297332aeb86accee6d41c67500;

function _getTokenManagerV4Storage()
private pure returns (TokenManagerV4Storage storage $)
{
assembly {
$.slot := Token_ManagerV4_Storage_Location
}
}

function getGateway() public view returns (address) {
TokenManagerStorage storage $ = _getTokenManagerStorage();
return $.gateway;
Expand All @@ -96,6 +141,11 @@ abstract contract TokenManagerUpgradeableV4 is
return $.remoteTokens[token][remoteChainId];
}

function getRemoteTokenScale(address token, uint remoteChainId) public view returns (int8) {
TokenManagerV4Storage storage $ = _getTokenManagerV4Storage();
return $.scaleForRemoteTokens[token][remoteChainId];
}

modifier onlyGateway() {
if (_msgSender() != address(getGateway())) {
revert NotGateway();
Expand All @@ -122,6 +172,8 @@ abstract contract TokenManagerUpgradeableV4 is
function _removeToken(address localToken, uint remoteChainId) internal {
TokenManagerStorage storage $ = _getTokenManagerStorage();
delete $.remoteTokens[localToken][remoteChainId];
TokenManagerV4Storage storage $$ = _getTokenManagerV4Storage();
delete $$.scaleForRemoteTokens[localToken][remoteChainId];
emit TokenRemoved(localToken, remoteChainId);
}

Expand All @@ -139,6 +191,49 @@ abstract contract TokenManagerUpgradeableV4 is
);
}

function _setScaleForToken(address localToken,
uint remoteChainId,
int8 scale) internal {
TokenManagerV4Storage storage $ = _getTokenManagerV4Storage();
$.scaleForRemoteTokens[localToken][remoteChainId] = scale;
emit TokenScaleChanged( localToken,
remoteChainId,
scale );
}


function _getScaleForToken(address localToken,
uint remoteChainId) internal returns (int8) {
TokenManagerV4Storage storage $ = _getTokenManagerV4Storage();
return $.scaleForRemoteTokens[localToken][remoteChainId];
}

function _scaleAmount(uint amount,
address localToken,
uint remoteChainId) internal returns (uint)
{
int8 scale = _getScaleForToken(localToken, remoteChainId);
uint adjusted;
uint reconstructed;

if (scale < 0) {
// Must be < 0 since the condition above requires it.
uint divisor = uint(10)**uint(int256(-scale));
adjusted = (amount / divisor);
reconstructed = amount * divisor;
} else if (scale > 0) {
// Must be > 0 since the condition above requires it.
uint multiplier = uint(10)**uint(int256(scale));
adjusted = amount * multiplier;
reconstructed = amount / multiplier;
}
// If scale == 0, nothing is done, which is what is intended.
if (adjusted != reconstructed) {
revert InvalidTokenAmount(amount, adjusted, reconstructed);
}
return adjusted;
}

// Token Overrides
function registerToken(
address token,
Expand Down Expand Up @@ -171,6 +266,13 @@ abstract contract TokenManagerUpgradeableV4 is
_unpause();
}

// V4 new function
function setScaleForToken(address localToken,
uint remoteChainId,
int8 scale) external virtual onlyOwner {
_setScaleForToken(localToken, remoteChainId, scale);
}

// TO OVERRIDE – Incoming
function _handleTransfer(
address token,
Expand All @@ -197,19 +299,25 @@ abstract contract TokenManagerUpgradeableV4 is
revert InvalidTokenRouting();
}

// If this does not exactly correspond with amount, _scaleAmount() will revert.
uint scaledAmount = _scaleAmount(amount, token, remoteChainId);

// We take the original amount.
_handleTransfer(token, _msgSender(), amount);

// .. and send the scaled amount.
IRelayer(getGateway()).relayWithMetadata(
remoteToken.chainId,
remoteToken.tokenManager,
this.accept.selector,
abi.encode(AcceptArgs(remoteToken.token, remoteRecipient, amount)),
abi.encode(AcceptArgs(remoteToken.token, remoteRecipient, scaledAmount)),
1_000_000
);
}

// Incoming
// No pausing here because we want incoming txns to go through that have already initiated
// We cannot scale anything here, because there's no way to stop the tokens having been sent.
function accept(
CallMetadata calldata metadata,
bytes calldata _args
Expand Down
48 changes: 24 additions & 24 deletions smart-contracts/script/pol/deploy/06_routing.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,31 @@ import {LockProxyTokenManagerUpgradeable} from "contracts/periphery/LockProxyTok
import {LockAndReleaseTokenManagerUpgradeable} from "contracts/periphery/LockAndReleaseTokenManagerUpgradeable.sol";
import {ITokenManagerStructs} from "contracts/periphery/TokenManagerUpgradeable.sol";

contract Routing is Script, MainnetConfig {
function run() external {

// Bridged: ['zil.1.6.52c256']
// Native: ['matic.1.17.3254b4']
// correspondent network: ['zilliqa']
LockProxyTokenManagerUpgradeable polLockProxyTokenManager = LockProxyTokenManagerUpgradeable(polLockProxyTokenManager)
LockAndReleaseTokenManagerUpgradeable polLockAndReleaseOrNativeTokenManager = LockAndReleaseTokenManagerUpgradeable(polLockAndReleaseOrNativeTokenManagerUpgradeable)
// bridged to polygon: token zil.1.6.52c256 has zq_denom zil.1.18.1a4a06, name ZIL and is on zilliqa as 0x0000000000000000000000000000000000000000, zil.1.18.1a4a06

ITokenManagerStructs.RemoteToken memory ZILBridgedTokenRouting = ITokenManagerStructs.RemoteToken({
token: address(0x0000000000000000000000000000000000000000),
tokenManager: address(zilLockAndReleaseOrNativeTokenManagerUpgradeable),
chainId: zqChainId });

polLockProxyTokenManager.registerToken(address(0xCc88D28f7d4B0D5AFACCC77F6102d88EE630fA17), ZILBridgedTokenRouting);
/* contract Routing is Script, MainnetConfig { */
/* function run() external { */

/* // Bridged: ['zil.1.6.52c256'] */
/* // Native: ['matic.1.17.3254b4'] */
/* // correspondent network: ['zilliqa'] */
/* LockProxyTokenManagerUpgradeable polLockProxyTokenManager = LockProxyTokenManagerUpgradeable(polLockProxyTokenManager); */
/* LockAndReleaseTokenManagerUpgradeable polLockAndReleaseOrNativeTokenManager = LockAndReleaseTokenManagerUpgradeable(polLockAndReleaseOrNativeTokenManagerUpgradeable); */
/* // bridged to polygon: token zil.1.6.52c256 has zq_denom zil.1.18.1a4a06, name ZIL and is on zilliqa as 0x0000000000000000000000000000000000000000, zil.1.18.1a4a06 */

/* ITokenManagerStructs.RemoteToken memory ZILBridgedTokenRouting = ITokenManagerStructs.RemoteToken({ */
/* token: address(0x0000000000000000000000000000000000000000), */
/* tokenManager: address(zilLockAndReleaseOrNativeTokenManagerUpgradeable), */
/* chainId: zqChainId }); */

/* polLockProxyTokenManager.registerToken(address(0xCc88D28f7d4B0D5AFACCC77F6102d88EE630fA17), ZILBridgedTokenRouting); */

// native on polygon: token matic.1.17.3254b4 has zq_denom zmatic.1.18.45185c, name zMATIC and is on zilliqa as 0xa1A172999AD3C5d457536c48736e30F53Bc260C9, zmatic.1.18.45185c
/* // native on polygon: token matic.1.17.3254b4 has zq_denom zmatic.1.18.45185c, name zMATIC and is on zilliqa as 0xa1A172999AD3C5d457536c48736e30F53Bc260C9, zmatic.1.18.45185c */

ITokenManagerStructs.RemoteToken memory zMATICNativeTokenRouting = ITokenManagerStructs.RemoteToken({
token: address(0xa1A172999AD3C5d457536c48736e30F53Bc260C9),
tokenManager: address(zilLockProxyTokenManager),
chainId: zqChainId });
polLockAndReleaseOrNativeTokenManager.registerToken(address(0x0000000000000000000000000000000000000000), zMATICNativeTokenRouting);
/* ITokenManagerStructs.RemoteToken memory zMATICNativeTokenRouting = ITokenManagerStructs.RemoteToken({ */
/* token: address(0xa1A172999AD3C5d457536c48736e30F53Bc260C9), */
/* tokenManager: address(zilLockProxyTokenManager), */
/* chainId: zqChainId }); */
/* polLockAndReleaseOrNativeTokenManager.registerToken(address(0x0000000000000000000000000000000000000000), zMATICNativeTokenRouting); */


}
}
/* } */
/* } */

0 comments on commit bc83607

Please sign in to comment.