Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better metadata reading to tokens from being stuck in the bridge #249

Merged
merged 4 commits into from
Mar 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 71 additions & 4 deletions contracts/lib/BridgeAssetOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {TokenWrapped} from "@RealityETH/zkevm-contracts/contracts/lib/TokenWrapp
import {ForkableBridge} from "../ForkableBridge.sol";
import {IForkonomicToken} from "../interfaces/IForkonomicToken.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC20MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

library BridgeAssetOperations {
// @dev Error thrown when forkable token is intended to be used, but it is not forkable
Expand Down Expand Up @@ -67,9 +67,9 @@ library BridgeAssetOperations {
revert TokenNotForkable();
}
bytes memory metadata = abi.encode(
IERC20Metadata(token).name(),
IERC20Metadata(token).symbol(),
IERC20Metadata(token).decimals()
_safeName(token),
_safeSymbol(token),
_safeDecimals(token)
);
ForkableBridge(child).mintForkableToken(
tokenInfo.originTokenAddress,
Expand Down Expand Up @@ -122,4 +122,71 @@ library BridgeAssetOperations {
IERC20(forkonomicToken2).transfer(child, amount);
}
}
// Helpers to safely get the metadata from a token, copied from here: https://github.com/0xPolygonHermez/zkevm-contracts/blob/d70266b8742672d59d4060019538d03fe0aac181/contracts/PolygonZkEVMBridge.sol#L800

/**
* @notice Provides a safe ERC20.symbol version which returns 'NO_SYMBOL' as fallback string
* @param token The address of the ERC-20 token contract
*/
function _safeSymbol(address token) internal view returns (string memory) {
(bool success, bytes memory data) = address(token).staticcall(
abi.encodeCall(IERC20MetadataUpgradeable.symbol, ())
);
return success ? _returnDataToString(data) : "NO_SYMBOL";
}

/**
* @notice Provides a safe ERC20.name version which returns 'NO_NAME' as fallback string.
* @param token The address of the ERC-20 token contract.
*/
function _safeName(address token) internal view returns (string memory) {
(bool success, bytes memory data) = address(token).staticcall(
abi.encodeCall(IERC20MetadataUpgradeable.name, ())
);
return success ? _returnDataToString(data) : "NO_NAME";
}

/**
* @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.
* Note Tokens with (decimals > 255) are not supported
* @param token The address of the ERC-20 token contract
*/
function _safeDecimals(address token) internal view returns (uint8) {
(bool success, bytes memory data) = address(token).staticcall(
abi.encodeCall(IERC20MetadataUpgradeable.decimals, ())
);
return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
}

/**
* @notice Function to convert returned data to string
* returns 'NOT_VALID_ENCODING' as fallback value.
* @param data returned data
*/
function _returnDataToString(
bytes memory data
) internal pure returns (string memory) {
if (data.length >= 64) {
return abi.decode(data, (string));
} else if (data.length == 32) {
// Since the strings on bytes32 are encoded left-right, check the first zero in the data
uint256 nonZeroBytes;
while (nonZeroBytes < 32 && data[nonZeroBytes] != 0) {
nonZeroBytes++;
}

// If the first one is 0, we do not handle the encoding
if (nonZeroBytes == 0) {
return "NOT_VALID_ENCODING";
}
// Create a byte array with nonZeroBytes length
bytes memory bytesArray = new bytes(nonZeroBytes);
for (uint256 i = 0; i < nonZeroBytes; i++) {
bytesArray[i] = data[i];
}
return string(bytesArray);
} else {
return "NOT_VALID_ENCODING";
}
}
}
Loading