Skip to content
Open
Show file tree
Hide file tree
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
Binary file not shown.
73 changes: 71 additions & 2 deletions contracts/TokenConverter/SingleTokenConverter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ contract SingleTokenConverter is AbstractTokenConverter {
/// @notice Address of the base asset token
address public baseAsset;

/// @notice The mapping contains the assets which are sent to destination directly
/// @dev Asset -> bool(should transfer directly on true)
mapping(address => bool) public assetsDirectTransfer;

/// @notice Emitted when base asset is updated
event BaseAssetUpdated(address indexed oldBaseAsset, address indexed newBaseAsset);

Expand All @@ -29,6 +33,20 @@ contract SingleTokenConverter is AbstractTokenConverter {
uint256 amount
);

/// @notice Emitted after the assetsDirectTransfer mapping is updated
event AssetsDirectTransferUpdated(address indexed receiver, address indexed asset, bool value);

/// @notice Thrown when the base asset is the same as the new base asset
error SameBaseAssetNotAllowed();

/// @notice Thrown if someone tries to add `baseAssets` to the `assetsDirectTransfer` collection
error DirectTransferBaseAssetNotAllowed();

/// @notice Thrown when the `assetsDirectTransfer[asset]` is already `value`
/// @param asset The asset address whose `assetDirectTransfer` value went to be set
/// @param value The value to be set
error SameAssetDirectTransferNotAllowed(address asset, bool value);

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
// Note that the contract is upgradeable. Use initialize() or reinitializers
Expand Down Expand Up @@ -56,11 +74,25 @@ contract SingleTokenConverter is AbstractTokenConverter {

/// @notice Sets the base asset for the contract
/// @param baseAsset_ The new address of the base asset
/// @custom:error ZeroAddressNotAllowed is thrown when address is zero
/// @custom:error SameBaseAssetNotAllowed is thrown when `baseAsset_` is equal to the current base asset
/// @custom:event BaseAssetUpdated is emitted on success
/// @custom:access Only Governance
function setBaseAsset(address baseAsset_) external onlyOwner {
_setBaseAsset(baseAsset_);
}

/// @notice Update the assetsDirectTransfer mapping
/// @param assets Addresses of the assets need to be added or removed for direct transfer
/// @param values Boolean value to indicate whether direct transfer is allowed for each asset.
/// @custom:event AssetsDirectTransferUpdated emits on success
/// @custom:error InputLengthMisMatch thrown when assets and values array lengths don't match
/// @custom:access Restricted by ACM
function setAssetsDirectTransfer(address[] calldata assets, bool[] calldata values) external virtual {
_checkAccessAllowed("setAssetsDirectTransfer(address[],bool[])");
_setAssetsDirectTransfer(assets, values);
}

/// @notice Get the balance for specific token
/// @param tokenAddress Address of the token
/// @return tokenBalance Balance of the token the contract has
Expand All @@ -69,16 +101,18 @@ contract SingleTokenConverter is AbstractTokenConverter {
tokenBalance = token.balanceOf(address(this));
}

/// @dev It returns the balance of the `asset` in this contract. If `asset` is the `baseAsset`
/// or `assetsDirectTransfer[asset]` is true, then the balance of `asset` in this contract will
/// be transferred to the `destinationAddress` and 0 will be returned
/// @param comptroller Comptroller address (pool)
/// @param asset Asset address.
/// @return balanceLeft Amount of asset, for _privateConversion
// solhint-disable-next-line
function _updateAssetsState(address comptroller, address asset) internal override returns (uint256 balanceLeft) {
IERC20Upgradeable token = IERC20Upgradeable(asset);
uint256 balance = token.balanceOf(address(this));
balanceLeft = balance;

if (asset == baseAsset) {
if (asset == baseAsset || assetsDirectTransfer[asset]) {
balanceLeft = 0;
token.safeTransfer(destinationAddress, balance);
emit AssetTransferredToDestination(destinationAddress, comptroller, asset, balance);
Expand Down Expand Up @@ -109,12 +143,47 @@ contract SingleTokenConverter is AbstractTokenConverter {
}
}

/// @dev Update the assetsDirectTransfer mapping for destinationAddress
/// @param assets Addresses of the assets need to be added or removed for direct transfer
/// @param values Boolean value to indicate whether direct transfer is allowed for each asset.
/// @custom:event AssetsDirectTransferUpdated emits on success
/// @custom:error InputLengthMisMatch thrown when assets and values array lengths don't match
/// @custom:error DirectTransferBaseAssetNotAllowed thrown when an asset in `assets` is the `baseAsset`
/// @custom:error SameAssetDirectTransferNotAllowed thrown when the value to set for an asset doesn't differs
/// from its current value
function _setAssetsDirectTransfer(address[] calldata assets, bool[] calldata values) internal {
uint256 assetsLength = assets.length;

if (assetsLength != values.length) {
revert InputLengthMisMatch();
}

for (uint256 i; i < assetsLength; ++i) {
if (assets[i] == baseAsset) {
revert DirectTransferBaseAssetNotAllowed();
}

if (assetsDirectTransfer[assets[i]] == values[i]) {
revert SameAssetDirectTransferNotAllowed(assets[i], values[i]);
}

assetsDirectTransfer[assets[i]] = values[i];
emit AssetsDirectTransferUpdated(destinationAddress, assets[i], values[i]);
}
}

/// @dev Sets the base asset for the contract
/// @param baseAsset_ The new address of the base asset
/// @custom:error ZeroAddressNotAllowed is thrown when address is zero
/// @custom:error SameBaseAssetNotAllowed is thrown when `baseAsset_` is equal to the current base asset
/// @custom:event BaseAssetUpdated is emitted on success
function _setBaseAsset(address baseAsset_) internal {
ensureNonzeroAddress(baseAsset_);

if (baseAsset == baseAsset_) {
revert SameBaseAssetNotAllowed();
}

emit BaseAssetUpdated(baseAsset, baseAsset_);
baseAsset = baseAsset_;
}
Expand Down
21 changes: 21 additions & 0 deletions deploy/006-update-single-token-converter-implementation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getNamedAccounts } = hre;
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();

await deploy("SingleTokenConverterImp", {
contract: "SingleTokenConverter",
from: deployer,
args: [],
log: true,
autoMine: true,
skipIfAlreadyDeployed: false,
});
};

func.tags = ["SingleTokenConverterImpl"];

export default func;
197 changes: 175 additions & 22 deletions deployments/arbitrumone/SingleTokenConverterImp.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

197 changes: 175 additions & 22 deletions deployments/bscmainnet/SingleTokenConverterImp.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

191 changes: 172 additions & 19 deletions deployments/bsctestnet/SingleTokenConverterImp.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

203 changes: 179 additions & 24 deletions deployments/ethereum/SingleTokenConverterImp.json

Large diffs are not rendered by default.

105 changes: 105 additions & 0 deletions deployments/ethereum/solcInputs/dceb6d0de70f90933a7f2cdf26a987ca.json

Large diffs are not rendered by default.

96 changes: 5 additions & 91 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import "module-alias/register";

import "@nomicfoundation/hardhat-chai-matchers";
import "@nomicfoundation/hardhat-toolbox";
import "@nomiclabs/hardhat-ethers";
import "@nomiclabs/hardhat-etherscan";
import "@nomicfoundation/hardhat-verify";
import "@openzeppelin/hardhat-upgrades";
import "@typechain/hardhat";
import dotenv from "dotenv";
Expand Down Expand Up @@ -254,57 +253,12 @@ const config: HardhatUserConfig = {
accounts: DEPLOYER_PRIVATE_KEY ? [`0x${DEPLOYER_PRIVATE_KEY}`] : [],
},
},
sourcify: {
enabled: true,
},
etherscan: {
apiKey: {
bscmainnet: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
bsctestnet: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
sepolia: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
ethereum: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
opbnbtestnet: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
opbnbmainnet: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
arbitrumsepolia: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
arbitrumone: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
opsepolia: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
opmainnet: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
basesepolia: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
basemainnet: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
unichainsepolia: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
unichainmainnet: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
berachainbartio: ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
},
apiKey: process.env.ETHERSCAN_API_KEY || "ETHERSCAN_API_KEY",
customChains: [
{
network: "bscmainnet",
chainId: 56,
urls: {
apiURL: "https://api.bscscan.com/api",
browserURL: "https://bscscan.com",
},
},
{
network: "bsctestnet",
chainId: 97,
urls: {
apiURL: "https://api-testnet.bscscan.com/api",
browserURL: "https://testnet.bscscan.com",
},
},
{
network: "sepolia",
chainId: 11155111,
urls: {
apiURL: "https://api-sepolia.etherscan.io/api",
browserURL: "https://sepolia.etherscan.io",
},
},
{
network: "ethereum",
chainId: 1,
urls: {
apiURL: "https://api.etherscan.io/api",
browserURL: "https://etherscan.io",
},
},
{
network: "opbnbtestnet",
chainId: 5611,
Expand All @@ -321,22 +275,6 @@ const config: HardhatUserConfig = {
browserURL: "https://opbnbscan.com/",
},
},
{
network: "arbitrumsepolia",
chainId: 421614,
urls: {
apiURL: `https://api-sepolia.arbiscan.io/api`,
browserURL: "https://sepolia.arbiscan.io/",
},
},
{
network: "arbitrumone",
chainId: 42161,
urls: {
apiURL: `https://api.arbiscan.io/api/`,
browserURL: "https://arbiscan.io/",
},
},
{
network: "opsepolia",
chainId: 11155420,
Expand All @@ -345,30 +283,6 @@ const config: HardhatUserConfig = {
browserURL: "https://sepolia-optimistic.etherscan.io/",
},
},
{
network: "opmainnet",
chainId: 10,
urls: {
apiURL: "https://api-optimistic.etherscan.io/api",
browserURL: "https://optimistic.etherscan.io/",
},
},
{
network: "basesepolia",
chainId: 84532,
urls: {
apiURL: "https://api-sepolia.basescan.org/api",
browserURL: "https://sepolia.basescan.org/",
},
},
{
network: "basemainnet",
chainId: 8453,
urls: {
apiURL: "https://api.basescan.org/api",
browserURL: "https://basescan.org/",
},
},
{
network: "unichainsepolia",
chainId: 1301,
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@
"@matterlabs/hardhat-zksync-verify": "0.7.0",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.3",
"@nomicfoundation/hardhat-network-helpers": "^1.0.4",
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^3.0.3",
"@nomicfoundation/hardhat-verify": "^2.0.14",
"@semantic-release/changelog": "^6.0.1",
"@semantic-release/git": "^10.0.1",
"@semantic-release/npm": "^9.0.1",
Expand Down
Loading