Skip to content

Commit

Permalink
πŸŠβ€β™‚οΈ Freeze Watr native token on blacklisting (#1256)
Browse files Browse the repository at this point in the history
* Freeze account on whitelisting

* Freeze native asset on pausing

* Revert "Freeze native asset on pausing"

This reverts commit c91e8bf.

* Update `IMintableXC20` interface

* Add blacklisting test to `verifyDeployments`
  • Loading branch information
abam-iksde authored Jun 23, 2023
1 parent 3dc9d59 commit f52112c
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 11 deletions.
12 changes: 12 additions & 0 deletions packages/contracts-watr/contracts/TrueCurrency.sol
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ abstract contract TrueCurrency is BurnableTokenWithBounds {
*/
function setBlacklisted(address account, bool _isBlacklisted) external override onlyOwner {
require(uint256(account) >= REDEMPTION_ADDRESS_COUNT, "TrueCurrency: blacklisting of redemption address is not allowed");
_setBlacklistedXC20(account, _isBlacklisted);
isBlacklisted[account] = _isBlacklisted;
emit Blacklisted(account, _isBlacklisted);
}
Expand Down Expand Up @@ -179,4 +180,15 @@ abstract contract TrueCurrency is BurnableTokenWithBounds {
function isRedemptionAddress(address account) internal pure returns (bool) {
return uint256(account) < REDEMPTION_ADDRESS_COUNT && account != address(0);
}

function _setBlacklistedXC20(address account, bool _isBlacklisted) internal {
if (isBlacklisted[account] == _isBlacklisted) {
return;
}
if (_isBlacklisted) {
_freeze(account);
} else {
_thaw(account);
}
}
}
26 changes: 17 additions & 9 deletions packages/contracts-watr/contracts/common/XC20Wrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {ClaimableOwnable} from "./ClaimableOwnable.sol";
import {IERC20Plus} from "../interface/IERC20Plus.sol";
import {IMintableXC20} from "../interface/IMintableXC20.sol";

abstract contract XC20Wrapper is IERC20, ClaimableOwnable, Context {
using SafeMath for uint256;

function totalSupply() public view virtual override returns (uint256) {
return IERC20Plus(nativeToken).totalSupply();
return IMintableXC20(nativeToken).totalSupply();
}

function balanceOf(address account) external view virtual override returns (uint256) {
return IERC20Plus(nativeToken).balanceOf(account);
return IMintableXC20(nativeToken).balanceOf(account);
}

function transfer(address recipient, uint256 amount) external virtual override returns (bool) {
Expand Down Expand Up @@ -54,7 +54,7 @@ abstract contract XC20Wrapper is IERC20, ClaimableOwnable, Context {
}

function decimals() public view virtual returns (uint8) {
return IERC20Plus(nativeToken).decimals();
return IMintableXC20(nativeToken).decimals();
}

function name() public pure virtual returns (string memory);
Expand All @@ -63,12 +63,12 @@ abstract contract XC20Wrapper is IERC20, ClaimableOwnable, Context {

function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "XC20: mint to the zero address");
IERC20Plus(nativeToken).mint(account, amount);
IMintableXC20(nativeToken).mint(account, amount);
emit Transfer(address(0), account, amount);
}

function _burn(address account, uint256 amount) internal virtual {
IERC20Plus(nativeToken).burn(account, amount);
IMintableXC20(nativeToken).burn(account, amount);
emit Transfer(account, address(0), amount);
}

Expand Down Expand Up @@ -97,8 +97,16 @@ abstract contract XC20Wrapper is IERC20, ClaimableOwnable, Context {
address recipient,
uint256 amount
) internal virtual {
require(IERC20Plus(nativeToken).balanceOf(sender) >= amount, "XC20: amount exceeds balance");
IERC20Plus(nativeToken).burn(sender, amount);
IERC20Plus(nativeToken).mint(recipient, amount);
require(IMintableXC20(nativeToken).balanceOf(sender) >= amount, "XC20: amount exceeds balance");
IMintableXC20(nativeToken).burn(sender, amount);
IMintableXC20(nativeToken).mint(recipient, amount);
}

function _freeze(address account) internal {
IMintableXC20(nativeToken).freeze(account);
}

function _thaw(address account) internal {
IMintableXC20(nativeToken).thaw(account);
}
}
14 changes: 14 additions & 0 deletions packages/contracts-watr/contracts/interface/IMintableXC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.10;

import {IERC20Plus} from "./IERC20Plus.sol";

interface IMintableXC20 is IERC20Plus {
function freeze(address account) external returns (bool);

function thaw(address account) external returns (bool);

function freezeAsset() external returns (bool);

function thawAsset() external returns (bool);
}
14 changes: 14 additions & 0 deletions packages/contracts-watr/contracts/mocks/MockXC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ contract MockXC20 {
mapping(address => uint256) public balanceOf;
uint8 public decimals;

mapping(address => bool) public frozen;

constructor(uint8 _decimals) public {
decimals = _decimals;
}
Expand All @@ -24,4 +26,16 @@ contract MockXC20 {

return true;
}

function freeze(address account) public returns (bool) {
frozen[account] = true;

return true;
}

function thaw(address account) public returns (bool) {
frozen[account] = false;

return true;
}
}
16 changes: 14 additions & 2 deletions packages/contracts-watr/test/TrueMintableBurnable.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, use } from 'chai'
import { solidity } from 'ethereum-waffle'
import { BigNumber, BigNumberish, constants, Wallet } from 'ethers'
import { MockXC20__factory, TrueUSD, TrueUSD__factory } from 'contracts'
import { MockXC20, MockXC20__factory, TrueUSD, TrueUSD__factory } from 'contracts'
import { beforeEachWithFixture } from 'fixtures/beforeEachWithFixture'
import { AddressZero, Zero } from '@ethersproject/constants'
import { parseEther } from '@ethersproject/units'
Expand All @@ -15,13 +15,14 @@ describe('TrueCurrency - Mint/Burn', () => {
let owner: Wallet
let initialHolder: Wallet
let secondAccount: Wallet
let mockXC20: MockXC20
let token: TrueUSD

const initialSupply = parseTrueUSD('1000')

beforeEachWithFixture(async (wallets) => {
[owner, initialHolder, secondAccount] = wallets
const mockXC20 = await new MockXC20__factory(owner).deploy(trueUSDDecimals)
mockXC20 = await new MockXC20__factory(owner).deploy(trueUSDDecimals)
token = await new TrueUSD__factory(owner).deploy()
await token.initialize(mockXC20.address)
await token.connect(owner).mint(initialHolder.address, initialSupply)
Expand Down Expand Up @@ -382,5 +383,16 @@ describe('TrueCurrency - Mint/Burn', () => {
await expect(token.setBlacklisted(AddressZero, true)).to.be.revertedWith('TrueCurrency: blacklisting of redemption address is not allowed')
})
})

describe('xc-20', () => {
it('calls "freeze" when blacklisting account', async () => {
expect(await mockXC20.frozen(blacklistedAccount.address)).to.be.true
})

it('calls "thaw" when de-blacklisting account', async () => {
await token.setBlacklisted(blacklistedAccount.address, false)
expect(await mockXC20.frozen(blacklistedAccount.address)).to.be.false
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ describe('verify deployment', () => {

await expect(tx).to.changeTokenBalances(token, [deployer, toAccount(otherAddress)], [parseEther('-0.5'), parseEther('0.5')])
}).timeout(100000)

it('can blacklist', async () => {
const deployer = new ethers.Wallet(process.env['PRIVATE_KEY_DEPLOYER'], provider)
const tokenController = TokenControllerV3__factory.connect(deployments.tokenControllerV3_proxy.address, deployer)
const otherAddress = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'

await waitFor(tokenController.setBlacklisted(otherAddress, true))
})
})

async function waitFor<T>(tx: Promise<{ wait: () => Promise<T> }>) {
Expand Down

1 comment on commit f52112c

@amirkhan7javi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will check for the claim of the property. There are access to the accessories.

Please sign in to comment.