Skip to content

Commit 30930b5

Browse files
committed
refactor: fix restrict logic in mock forest
Signed-off-by: MASDXI <sirawitt42@gmail.com>
1 parent 2e64218 commit 30930b5

File tree

10 files changed

+152
-98
lines changed

10 files changed

+152
-98
lines changed

contracts/abstracts/ForestToken.sol

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ abstract contract ForestToken is ERC20, IForestERC20 {
3232
return _dag.getTx(tokenId);
3333
}
3434

35+
function transactionLevel(bytes32 tokenId) internal view returns (uint256) {
36+
return _dag.getTxLevel(tokenId);
37+
}
38+
39+
function transactionParent(bytes32 tokenId) internal view returns (bytes32) {
40+
return _dag.getTxParent(tokenId);
41+
}
42+
43+
function transactionRoot(bytes32 tokenId) internal view returns (bytes32) {
44+
return _dag.getTxRoot(tokenId);
45+
}
46+
47+
function transactionValue(bytes32 tokenId) internal view returns (uint256) {
48+
return _dag.getTxValue(tokenId);
49+
}
50+
51+
function transactionCount(address account) internal view returns (uint256) {
52+
return _dag.getTxCount(account);
53+
}
54+
55+
function transactionHierarchy(bytes32 tokenId) internal view returns (uint256) {
56+
return _dag.getTxHierarchy(tokenId);
57+
}
58+
3559
/**
3660
* @dev Internal function to transfer tokens and manage transactions within the forest.
3761
* @param from The sender address.

contracts/abstracts/extensions/FreezeAddress.sol

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,11 @@ pragma solidity >=0.8.0 <0.9.0;
99
abstract contract FreezeAddress {
1010
mapping(address => bool) private _frozen;
1111

12-
/**
13-
* @notice Error thrown when an operation is attempted on a frozen address.
14-
*/
12+
/** errors */
1513
error AddressFrozen();
16-
17-
/**
18-
* @notice Error thrown when an operation is attempted to unfreeze an address that is not frozen.
19-
*/
2014
error AddressNotFrozen();
2115

22-
/**
23-
* @notice Event emitted when an address is frozen or unfrozen.
24-
* @param account The address that was frozen or unfrozen.
25-
* @param auth The boolean status indicating if the address is frozen (true) or unfrozen (false).
26-
*/
16+
/** events */
2717
event FrozeAddress(address indexed account, bool indexed auth);
2818

2919
modifier checkFrozenAddress(address from, address to) {

contracts/abstracts/extensions/FreezeBalance.sol

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,11 @@ pragma solidity >=0.8.0 <0.9.0;
99
abstract contract FreezeBalance {
1010
mapping(address => uint256) private _frozenBalance;
1111

12-
/**
13-
* @notice Error thrown when an operation causes a balance overflow.
14-
*/
12+
/** errors */
1513
error BalanceOverflow();
16-
17-
/**
18-
* @notice Error thrown when a frozen balance restriction is violated.
19-
* @param balance The total balance of the account.
20-
* @param frozenBalance The frozen balance of the account.
21-
*/
2214
error BalanceFrozen(uint256 balance, uint256 frozenBalance);
2315

24-
/**
25-
* @notice Event emitted when an account's balance is frozen or unfrozen.
26-
* @param account The address of the account.
27-
* @param value The amount of balance that is frozen.
28-
*/
16+
/** events */
2917
event FrozenBalance(address indexed account, uint256 value);
3018

3119
/**

contracts/abstracts/extensions/FreezeToken.sol

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,11 @@ pragma solidity >=0.8.0 <0.9.0;
99
abstract contract FreezeToken {
1010
mapping(bytes32 => bool) private _frozenToken;
1111

12-
/**
13-
* @notice Error thrown when a token operation is attempted on a frozen token.
14-
*/
12+
/** errors */
1513
error TokenFrozen();
16-
17-
/**
18-
* @notice Error thrown when an operation is attempted to unfreeze a token that is not frozen.
19-
*/
2014
error TokenNotFrozen();
2115

22-
/**
23-
* @notice Event emitted when a token is frozen or unfrozen.
24-
* @param tokenId The identifier of the token.
25-
* @param auth The status of the token, true if frozen, false if unfrozen.
26-
*/
16+
/** events */
2717
event frozenToken(bytes32 indexed tokenId, bool indexed auth);
2818

2919
/**

contracts/libraries/Forest.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ library Forest {
6868
function createTx(DAG storage self, Tx memory newTx, address spender) internal {
6969
if (newTx.value == 0) revert TransactionZeroValue();
7070
bytes32 newId = calcTxHash(spender, self.nonces[spender]);
71-
self.txs[newId] = newTx;
71+
self.txs[newId] = Tx(newId, newTx.parent, newTx.value, newTx.level, newTx.owner);
7272
unchecked {
7373
self.nonces[spender]++;
7474
}

contracts/mocks/MockForest.sol

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ import "../abstracts/extensions/FreezeBalance.sol";
77
import "../abstracts/extensions/FreezeToken.sol";
88

99
contract MockForest is ForestToken, FreezeAddress, FreezeBalance, FreezeToken {
10+
enum RESTRICT_TYPES { NULL, EQUAL, LESS, GREATER, BETWEEN }
11+
12+
struct Restrict {
13+
RESTRICT_TYPES types;
14+
bool enable;
15+
uint256 start;
16+
uint256 end;
17+
}
18+
19+
mapping(bytes32 => Restrict) private _restricts;
20+
1021
/// @custom:event for keep tracking token from root.
1122
event Transfer(address from, address to, bytes32 indexed root, bytes32 indexed parent, uint256 value);
1223

@@ -20,30 +31,51 @@ contract MockForest is ForestToken, FreezeAddress, FreezeBalance, FreezeToken {
2031
_;
2132
}
2233

23-
// TODO
24-
// modifier checkFrozenLevel(bytes32 tokenId) {
25-
// check root equal check equal
26-
// _;
27-
// }
28-
29-
// TODO
30-
// modifier checkFrozenBeforeLevel(bytes32 tokenId)
31-
// check root equal and check less than
32-
// _;
33-
// }
34+
modifier checkFrozenLevel(bytes32 tokenId) {
35+
Restrict memory restrict = getPartition(tokenId);
36+
if (restrict.types == RESTRICT_TYPES.EQUAL && (restrict.enable)) {
37+
if (transactionLevel(tokenId) == restrict.start) {
38+
revert TokenFrozen();
39+
}
40+
}
41+
_;
42+
}
3443

35-
// TODO
36-
// modifier checkFrozenAfterLevel(bytes32 tokenId)
37-
// check root equal check greater than
38-
// _;
39-
// }
44+
modifier checkFrozenBeforeLevel(bytes32 tokenId) {
45+
Restrict memory restrict = getPartition(tokenId);
46+
if (restrict.types == RESTRICT_TYPES.LESS && (restrict.enable)) {
47+
if (transactionLevel(tokenId) < restrict.start) {
48+
revert TokenFrozen();
49+
}
50+
}
51+
_;
52+
}
53+
54+
modifier checkFrozenAfterLevel(bytes32 tokenId) {
55+
Restrict memory restrict = getPartition(tokenId);
56+
uint256 txLevel = transactionLevel(tokenId);
57+
if (restrict.types == RESTRICT_TYPES.GREATER && (restrict.enable)) {
58+
if (transactionLevel(tokenId) > restrict.start && txLevel < restrict.end) {
59+
revert TokenFrozen();
60+
}
61+
}
62+
_;
63+
}
4064

41-
// TODO
42-
// modifier checkFrozenInBetweenLevel(bytes32 tokenId)
65+
/** @dev restrict in partitioning style */
66+
modifier checkFrozenInBetweenLevel(bytes32 tokenId) {
4367
// check root equal check greater than 'x' and less than 'y'
44-
// _;
45-
// }
46-
68+
Restrict memory restrict = getPartition(tokenId);
69+
uint256 txLevel = transactionLevel(tokenId);
70+
if (restrict.types == RESTRICT_TYPES.BETWEEN && (restrict.enable)) {
71+
if (txLevel > restrict.start && txLevel < restrict.end) {
72+
revert TokenFrozen();
73+
}
74+
}
75+
_;
76+
}
77+
78+
/** @notice ERC20 Transfer also emit. */
4779
function _transfer(
4880
address from,
4981
address to,
@@ -58,7 +90,7 @@ contract MockForest is ForestToken, FreezeAddress, FreezeBalance, FreezeToken {
5890
checkFrozenRootOrParent(tokenId)
5991
checkFrozenToken(tokenId)
6092
{
61-
/// @notice ERC20 Transfer also emit.
93+
6294
super._transfer(from, to, tokenId, value);
6395
Forest.Tx memory txn = _transaction(tokenId);
6496
emit Transfer(from, to, txn.root, txn.parent, value);
@@ -71,4 +103,20 @@ contract MockForest is ForestToken, FreezeAddress, FreezeBalance, FreezeToken {
71103
function burn(address account, bytes32 tokenId, uint256 value) public {
72104
_burnTransaction(account, tokenId, value);
73105
}
106+
107+
function setPartition(bytes32 tokenId, uint256 start, uint256 end, RESTRICT_TYPES restrict) public {
108+
bytes32 rootTokenId = transactionRoot(tokenId);
109+
_restricts[rootTokenId].types = restrict;
110+
_restricts[rootTokenId].enable = true;
111+
_restricts[rootTokenId].start = start;
112+
_restricts[rootTokenId].end = end;
113+
}
114+
115+
function clearPartition(bytes32 tokenId) public {
116+
delete _restricts[transactionRoot(tokenId)];
117+
}
118+
119+
function getPartition(bytes32 tokenId) public view returns (Restrict memory) {
120+
return _restricts[transactionRoot(tokenId)];
121+
}
74122
}

test/contracts/ERC20/ERC20.test.js

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
const {loadFixture} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
2-
const {network} = require("hardhat");
3-
const {anyValue} = require("@nomicfoundation/hardhat-chai-matchers/withArgs");
42
const {expect} = require("chai");
5-
const {ZeroAddress} = require("ethers");
3+
const {amount, frozenAmount, tokenMetadata} = require("../../utils/constant");
64

5+
// skipping to test the ERC20 behavior because inherit from @openzeppelin/contracts
76
describe("ERC20", function () {
8-
const amount = 1000n;
9-
const frozenAmount = 100n;
10-
117
async function deployTokenFixture() {
128
const [owner, alice, bob, charlie, dave, otherAccount] = await ethers.getSigners();
139
const contract = await ethers.getContractFactory("MockERC20");
14-
const token = await contract.deploy("United States dollar", "USD");
10+
const token = await contract.deploy(tokenMetadata.name, tokenMetadata.symbol);
11+
1512
return {token, owner, alice, bob, charlie, dave, otherAccount};
1613
}
1714

@@ -20,7 +17,7 @@ describe("ERC20", function () {
2017
const {token, alice, bob} = await loadFixture(deployTokenFixture);
2118
const aliceAddress = alice.address;
2219
const bobAddress = bob.address;
23-
await token.mint(alice, amount);
20+
await token.mint(aliceAddress, amount);
2421
await token.freezeAddress(aliceAddress);
2522
expect(await token.isFrozen(aliceAddress)).to.equal(true);
2623
await expect(token.connect(alice).transfer(bobAddress, amount)).to.be.reverted;
@@ -30,19 +27,18 @@ describe("ERC20", function () {
3027
const {token, owner, alice, bob} = await loadFixture(deployTokenFixture);
3128
const spenderAddress = owner.address;
3229
const aliceAddress = alice.address;
33-
const bobAddress = bob.address;
34-
await token.mint(alice, amount);
30+
await token.mint(aliceAddress, amount);
3531
await token.connect(alice).approve(spenderAddress, amount);
3632
await token.freezeAddress(aliceAddress);
3733
expect(await token.isFrozen(aliceAddress)).to.equal(true);
38-
await expect(token.connect(owner).transferFrom(aliceAddress, bobAddress, amount)).to.be.reverted;
34+
await expect(token.connect(owner).transferFrom(aliceAddress, bob.address, amount)).to.be.reverted;
3935
});
4036

4137
it("Freeze Alice Balance and transfer", async function () {
4238
const {token, alice, bob} = await loadFixture(deployTokenFixture);
4339
const aliceAddress = alice.address;
4440
const bobAddress = bob.address;
45-
await token.mint(alice, amount);
41+
await token.mint(aliceAddress, amount);
4642
await token.setFreezeBalance(aliceAddress, frozenAmount);
4743
expect(await token.getFrozenBalance(aliceAddress)).to.equal(frozenAmount);
4844
await expect(token.connect(alice).transfer(bobAddress, amount - frozenAmount)).not.to.be.reverted;

test/contracts/Forest/Forest.test.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,56 @@ const {anyValue} = require("@nomicfoundation/hardhat-chai-matchers/withArgs");
33
const {network} = require("hardhat");
44
const {expect} = require("chai");
55
const {encodeBytes32String, ZeroAddress, solidityPackedKeccak256, getBytes} = require("ethers");
6+
const {amount, freezeAmount, transferFrom, transfer, tokenMetadata} = require("../../utils/constant");
67

78
describe("Forest", function () {
8-
const transferMethod = "transfer(address,bytes32,uint256)";
9-
109
async function deployTokenFixture() {
1110
const [owner, otherAccount] = await ethers.getSigners();
1211
const contract = await ethers.getContractFactory("MockForest");
13-
const token = await contract.deploy("United States dollar", "USD");
12+
const token = await contract.deploy(tokenMetadata.name, tokenMetadata.symbol);
13+
1414
return {token, owner, otherAccount};
1515
}
1616

1717
describe("Scenarios", function () {
1818
it("Freeze Alice Account and transfer", async function () {
19-
// TODO
19+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
2020
});
2121

2222
it("Freeze Alice Account and transferFrom", async function () {
23-
// TODO
23+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
2424
});
2525

2626
it("Freeze Alice Balance and transfer", async function () {
27-
// TODO
27+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
2828
});
2929

3030
it("Freeze Alice Balance and transferFrom", async function () {
31-
// TODO
31+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
3232
});
3333

3434
it("Freeze Alice Token and transfer", async function () {
35-
// TODO
35+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
3636
});
3737

3838
it("Freeze Alice Token and transferFrom", async function () {
39-
// TODO
39+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
4040
});
4141

4242
it("Freeze at root and transfer", async function () {
43-
// TODO
43+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
4444
});
4545

4646
it("Freeze at root and transferFrom", async function () {
47-
// TODO
47+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
4848
});
4949

5050
it("Freeze at level and transfer", async function () {
51-
// TODO
51+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
5252
});
5353

5454
it("Freeze at level and transferFrom", async function () {
55-
// TODO
55+
const {token, alice, bob} = await loadFixture(deployTokenFixture);
5656
});
5757
});
5858
});

0 commit comments

Comments
 (0)