diff --git a/contracts/bridges/OriginalTokenBridgeUpgradable.sol b/contracts/bridges/OriginalTokenBridgeUpgradable.sol index 01bf503..09ead8b 100644 --- a/contracts/bridges/OriginalTokenBridgeUpgradable.sol +++ b/contracts/bridges/OriginalTokenBridgeUpgradable.sol @@ -33,6 +33,7 @@ contract OriginalTokenBridgeUpgradable is TokenBridgeBaseUpgradable { event ReceiveToken(address token, address to, uint amount); event SetRemoteChainId(uint16 remoteChainId); event RegisterToken(address token); + event DeregisterToken(address token); event WithdrawFee(address indexed token, address to, uint amount); event Paused(address account); event Unpaused(address account); @@ -64,6 +65,12 @@ contract OriginalTokenBridgeUpgradable is TokenBridgeBaseUpgradable { emit RegisterToken(token); } + function deregisterToken(address token) external onlyOwner { + require(supportedTokens[token], "OriginalTokenBridge: token is not registered"); + supportedTokens[token] = false; + LDtoSDConversionRate[token] = 0; + emit DeregisterToken(token); + } function setRemoteChainId(uint16 _remoteChainId) external onlyOwner { remoteChainId = _remoteChainId; emit SetRemoteChainId(_remoteChainId); diff --git a/contracts/bridges/WrappedTokenBridgeUpgradable.sol b/contracts/bridges/WrappedTokenBridgeUpgradable.sol index 2eff9b7..21f79af 100644 --- a/contracts/bridges/WrappedTokenBridgeUpgradable.sol +++ b/contracts/bridges/WrappedTokenBridgeUpgradable.sol @@ -54,6 +54,18 @@ contract WrappedTokenBridgeUpgradable is TokenBridgeBaseUpgradable { emit RegisterToken(localToken, remoteChainId, remoteToken); } + function updateToken(address localToken, uint16 remoteChainId, address remoteToken) external onlyOwner { + require(localToken != address(0), "WrappedTokenBridge: invalid local token"); + require(remoteToken != address(0), "WrappedTokenBridge: invalid remote token"); + require(localToRemote[localToken][remoteChainId] != address(0) && remoteToLocal[remoteToken][remoteChainId] == address(0), "WrappedTokenBridge: token not registered"); + address oldRemoteToken = localToRemote[localToken][remoteChainId]; + require(totalValueLocked[remoteChainId][oldRemoteToken] == 0, "WrappedTokenBridge: token has locked value"); + + localToRemote[localToken][remoteChainId] = remoteToken; + remoteToLocal[remoteToken][remoteChainId] = localToken; + emit RegisterToken(localToken, remoteChainId, remoteToken); + } + function setWithdrawalFeeBps(uint16 _withdrawalFeeBps) external onlyOwner { require(_withdrawalFeeBps < TOTAL_BPS, "WrappedTokenBridge: invalid withdrawal fee bps"); withdrawalFeeBps = _withdrawalFeeBps; diff --git a/test/OriginalTokenBridge.test.js b/test/OriginalTokenBridge.test.js index 9b60488..2b3bbfc 100644 --- a/test/OriginalTokenBridge.test.js +++ b/test/OriginalTokenBridge.test.js @@ -80,6 +80,25 @@ describe("OriginalTokenBridge", () => { }) }) + describe("deregisterToken", () => { + beforeEach(async () => { + await originalTokenBridge.registerToken(originalToken.target, sharedDecimals) + }) + + it("reverts if token is not registered", async () => { + await expect(originalTokenBridge.deregisterToken(weth.target)).to.be.revertedWith("OriginalTokenBridge: token is not registered") + }) + + it("reverts when called by non owner", async () => { + await expect(originalTokenBridge.connect(user).deregisterToken(originalToken.target)).to.be.revertedWith("Ownable: caller is not the owner") + }) + + it("deregisters token", async () => { + await originalTokenBridge.deregisterToken(originalToken.target) + expect(await originalTokenBridge.supportedTokens(originalToken.target)).to.be.false + }) + }) + describe("setRemoteChainId", () => { const newRemoteChainId = 2 it("reverts when called by non owner", async () => { diff --git a/test/WrappedTokenBridge.test.js b/test/WrappedTokenBridge.test.js index 4303d7c..2c52b38 100644 --- a/test/WrappedTokenBridge.test.js +++ b/test/WrappedTokenBridge.test.js @@ -75,6 +75,34 @@ describe("WrappedTokenBridge", () => { }) }) + describe("updateToken", () => { + it("reverts when called by non owner", async () => { + await expect(wrappedTokenBridge.connect(user).updateToken(wrappedToken.target, originalTokenChainId, originalToken.target)).to.be.revertedWith("Ownable: caller is not the owner") + }) + + it("reverts when local token is address zero", async () => { + await expect(wrappedTokenBridge.updateToken(ZeroAddress, originalTokenChainId, originalToken.target)).to.be.revertedWith("WrappedTokenBridge: invalid local token") + }) + + it("reverts when remote token is address zero", async () => { + await expect(wrappedTokenBridge.updateToken(wrappedToken.target, originalTokenChainId, ZeroAddress)).to.be.revertedWith("WrappedTokenBridge: invalid remote token") + }) + + it("reverts if token isn't registered", async () => { + await expect(wrappedTokenBridge.updateToken(wrappedToken.target, originalTokenChainId, originalToken.target)).to.be.revertedWith("WrappedTokenBridge: token not registered") + }) + + it("updates tokens", async () => { + const ERC20Factory = await ethers.getContractFactory("MintableERC20Mock") + const originalToken2 = await ERC20Factory.deploy("TEST", "TEST") + await wrappedTokenBridge.registerToken(wrappedToken.target, originalTokenChainId, originalToken.target) + await wrappedTokenBridge.updateToken(wrappedToken.target, originalTokenChainId, originalToken2.target) + + expect(await wrappedTokenBridge.localToRemote(wrappedToken.target, originalTokenChainId)).to.be.eq(originalToken2.target) + expect(await wrappedTokenBridge.remoteToLocal(originalToken2.target, originalTokenChainId)).to.be.eq(wrappedToken.target) + }) + }) + describe("setWithdrawalFeeBps", () => { const withdrawalFeeBps = 10 it("reverts when fee bps is greater than or equal to 100%", async () => {