Skip to content

Commit

Permalink
Merge pull request #12 from VenusProtocol/feat/migrate-minted-tokens
Browse files Browse the repository at this point in the history
[VEN-2240]: support of replacement of dest bridge
  • Loading branch information
GitGuru7 authored Dec 28, 2023
2 parents 91b640f + d465299 commit db750ce
Show file tree
Hide file tree
Showing 38 changed files with 9,988 additions and 675 deletions.
27 changes: 27 additions & 0 deletions contracts/Bridge/XVSProxyOFTSrc.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ contract XVSProxyOFTSrc is BaseXVSProxyOFT {
* @notice Emits when stored message dropped without successful retrying.
*/
event DropFailedMessage(uint16 srcChainId, bytes indexed srcAddress, uint64 nonce);
/**
* @notice Event emitted when tokens are forcefully locked.
*/
event FallbackDeposit(address indexed from, uint256 amount_);

constructor(
address tokenAddress_,
Expand All @@ -53,6 +57,25 @@ contract XVSProxyOFTSrc is BaseXVSProxyOFT {
emit FallbackWithdraw(to_, amount_);
}

/**
* @notice Forces the lock of tokens by increasing outbound amount and transferring tokens from the sender to the contract.
* @param amount_ The amount of tokens to lock.
* @param depositor_ Address of the depositor.
* @custom:access Only owner.
* @custom:event Emits FallbackDeposit, once done with transfer.
*/
function fallbackDeposit(address depositor_, uint256 amount_) external onlyOwner {
(uint256 actualAmount, ) = _removeDust(amount_);

outboundAmount += actualAmount;
uint256 cap = _sd2ld(type(uint64).max);
require(cap >= outboundAmount, "ProxyOFT: outboundAmount overflow");

_transferFrom(depositor_, address(this), actualAmount);

emit FallbackDeposit(depositor_, actualAmount);
}

/**
* @notice Clear failed messages from the storage.
* @param srcChainId_ Chain id of source
Expand Down Expand Up @@ -91,7 +114,11 @@ contract XVSProxyOFTSrc is BaseXVSProxyOFT {
_isEligibleToSend(from_, dstChainId_, amount_);

uint256 amount = _transferFrom(from_, address(this), amount_);

outboundAmount += amount;
uint256 cap = _sd2ld(type(uint64).max);
require(cap >= outboundAmount, "ProxyOFT: outboundAmount overflow");

return amount;
}

Expand Down
63 changes: 62 additions & 1 deletion contracts/Bridge/token/TokenController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ contract TokenController is Ownable, Pausable {
* @notice Emitted when the address of the access control manager of the contract is updated.
*/
event NewAccessControlManager(address indexed oldAccessControlManager, address indexed newAccessControlManager);
/**
* @notice Emitted when all minted tokens are migrated from one minter to another.
*/
event MintedTokensMigrated(address indexed source, address indexed destination);

/**
* @notice This error is used to indicate that the minting limit has been exceeded. It is typically thrown when a minting operation would surpass the defined cap.
Expand All @@ -68,6 +72,14 @@ contract TokenController is Ownable, Pausable {
* @notice This error is used to indicate that the new cap is greater than the previously minted tokens for the minter.
*/
error NewCapNotGreaterThanMintedTokens();
/**
* @notice This error is used to indicate that the addresses must be different.
*/
error AddressesMustDiffer();
/**
* @notice This error is used to indicate that the minter did not mint the required amount of tokens.
*/
error MintedAmountExceed();

/**
* @param accessControlManager_ Address of access control manager contract.
Expand Down Expand Up @@ -141,6 +153,46 @@ contract TokenController is Ownable, Pausable {
accessControlManager = newAccessControlAddress_;
}

/**
* @notice Migrates all minted tokens from one minter to another. This function is useful when we want to permanent take down a bridge.
* @param source_ Minter address to migrate tokens from.
* @param destination_ Minter address to migrate tokens to.
* @custom:access Controlled by AccessControlManager.
* @custom:error MintLimitExceed is thrown when the minting limit exceeds the cap after migration.
* @custom:error AddressesMustDiffer is thrown when the source_ and destination_ addresses are the same.
* @custom:event Emits MintLimitIncreased and MintLimitDecreased events for 'source' and 'destination'.
* @custom:event Emits MintedTokensMigrated.
*/
function migrateMinterTokens(address source_, address destination_) external {
_ensureAllowed("migrateMinterTokens(address,address)");

if (source_ == destination_) {
revert AddressesMustDiffer();
}

uint256 sourceCap = minterToCap[source_];
uint256 destinationCap = minterToCap[destination_];

uint256 sourceMinted = minterToMintedAmount[source_];
uint256 destinationMinted = minterToMintedAmount[destination_];
uint256 newDestinationMinted = destinationMinted + sourceMinted;

if (newDestinationMinted > destinationCap) {
revert MintLimitExceed();
}

minterToMintedAmount[source_] = 0;
minterToMintedAmount[destination_] = newDestinationMinted;
uint256 availableLimit;
unchecked {
availableLimit = destinationCap - newDestinationMinted;
}

emit MintLimitDecreased(destination_, availableLimit);
emit MintLimitIncreased(source_, sourceCap);
emit MintedTokensMigrated(source_, destination_);
}

/**
* @notice Returns the blacklist status of the address.
* @param user_ Address of user to check blacklist status.
Expand Down Expand Up @@ -178,11 +230,20 @@ contract TokenController is Ownable, Pausable {
* @dev This is post hook of burn function, increases minting limit of the minter.
* @param from_ Minter address.
* @param amount_ Amount burned.
* @custom:error MintedAmountExceed is thrown when `amount_` is greater than the tokens minted by `from_`.
* @custom:event Emits MintLimitIncreased with minter address and availabe limit.
*/
function _increaseMintLimit(address from_, uint256 amount_) internal {
uint256 totalMintedOld = minterToMintedAmount[from_];
uint256 totalMintedNew = totalMintedOld - amount_;

if (totalMintedOld < amount_) {
revert MintedAmountExceed();
}

uint256 totalMintedNew;
unchecked {
totalMintedNew = totalMintedOld - amount_;
}
minterToMintedAmount[from_] = totalMintedNew;
uint256 availableLimit = minterToCap[from_] - totalMintedNew;
emit MintLimitIncreased(from_, availableLimit);
Expand Down
12 changes: 6 additions & 6 deletions deploy/001-xvs-bridge-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

import {
bridgeAdminMethods,
XVSBridgeAdminMethods,
bridgeConfig,
getPreConfiguredAddresses,
xvsBridgeMethods,
xvsBridgeMethodsSrc,
} from "../helpers/deploymentConfig";
import { toAddress } from "../helpers/utils";
import { getArgTypesFromSignature } from "../helpers/utils";
Expand Down Expand Up @@ -102,8 +102,8 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const bridge = await ethers.getContract("XVSProxyOFTSrc");
const bridgeAdmin = await ethers.getContract("XVSBridgeAdmin");

const removeArray = new Array(xvsBridgeMethods.length).fill(true);
let tx = await bridgeAdmin.upsertSignature(xvsBridgeMethods, removeArray);
const removeArray = new Array(xvsBridgeMethodsSrc.length).fill(true);
let tx = await bridgeAdmin.upsertSignature(xvsBridgeMethodsSrc, removeArray);
await tx.wait();

tx = await bridge.transferOwnership(XVSBridgeAdmin.address);
Expand All @@ -117,14 +117,14 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

const commands = [
...(await configureAccessControls(
xvsBridgeMethods,
xvsBridgeMethodsSrc,
accessControlManager.address,
normalTimelock.address,
XVSBridgeAdmin.address,
hre,
)),
...(await configureAccessControls(
bridgeAdminMethods,
XVSBridgeAdminMethods,
accessControlManager.address,
normalTimelock.address,
XVSBridgeAdmin.address,
Expand Down
19 changes: 10 additions & 9 deletions deploy/002-xvs-bridge-remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

import {
bridgeAdminMethods,
XVSBridgeAdminMethods,
XVSTokenDestMethods,
bridgeConfig,
getPreConfiguredAddresses,
xvsBridgeMethods,
xvsBridgeMethodsDest,
xvsTokenPermissions,
} from "../helpers/deploymentConfig";
import { toAddress } from "../helpers/utils";
Expand Down Expand Up @@ -129,8 +130,8 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

await executeBridgeCommands(bridge, hre, deployer);

const removeArray = new Array(xvsBridgeMethods.length).fill(true);
let tx = await bridgeAdmin.upsertSignature(xvsBridgeMethods, removeArray);
const removeArray = new Array(xvsBridgeMethodsDest.length).fill(true);
let tx = await bridgeAdmin.upsertSignature(xvsBridgeMethodsDest, removeArray);
await tx.wait();

tx = await xvs.transferOwnership(preconfiguredAddresses.NormalTimelock);
Expand All @@ -147,7 +148,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

const commands = [
...(await configureAccessControls(
xvsBridgeMethods,
xvsBridgeMethodsDest,
accessControlManager.address,
preconfiguredAddresses.NormalTimelock,
XVSBridgeAdmin.address,
Expand All @@ -163,18 +164,18 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
)),

...(await configureAccessControls(
["setMintCap(address,uint256)"],
XVSBridgeAdminMethods,
accessControlManager.address,
preconfiguredAddresses.NormalTimelock,
XVS.address,
XVSBridgeAdmin.address,
hre,
)),

...(await configureAccessControls(
bridgeAdminMethods,
XVSTokenDestMethods,
accessControlManager.address,
preconfiguredAddresses.NormalTimelock,
XVSBridgeAdmin.address,
XVS.address,
hre,
)),

Expand Down
Loading

0 comments on commit db750ce

Please sign in to comment.