Skip to content

Commit 32d3095

Browse files
ZigBalthazarkehiy
andauthored
fix: fee calculation logic (#10)
Co-authored-by: Kay <kehiiiiya@gmail.com>
1 parent 85f8e26 commit 32d3095

File tree

10 files changed

+82
-21
lines changed

10 files changed

+82
-21
lines changed

.github/workflows/unit-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ jobs:
2828
run: npm install
2929

3030
- name: Run Hardhat tests
31-
run: npx hardhat test
31+
run: npm run test

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Welcome to the repository for Wrapped PAC (WPAC) token. WPAC is a wrapped token
44

55
## Project Overview
66

7-
WPAC tokens are wrapped tokens of the Teleport Protocol contracts. The token contract is implemented in Solidity and follows the OpenZeppelin Contracts upgradeable pattern. It allows users to bridge PAC tokens from one blockchain to another by locking the tokens in the contract and minting WPAC tokens on the destination chain.
7+
WPAC tokens are wrapped tokens of the Wrapto contracts. The token contract is implemented in Solidity and follows the OpenZeppelin Contracts upgradeable pattern. It allows users to bridge PAC tokens from one blockchain to another by locking the tokens in the contract and minting WPAC tokens on the destination chain.
88

99
## Getting Started
1010

@@ -42,7 +42,8 @@ In the project directory, you can run the following scripts:
4242

4343
## Contract Overview
4444

45-
The main contract file is `WrappedPAC.sol` which implements the ERC20 interface. It also integrates functionalities for bridging PAC tokens from one blockchain to another. The contract is upgradeable and follows the Ownable and Pausable patterns for security and control.
45+
The main contract file is `wpac.sol` which implements the ERC20 interface. It also integrates functionalities for bridging PAC tokens from one blockchain to another. The contract is upgradeable and follows the Ownable and Pausable patterns for security and control.
46+
4647

4748
## Project Structure
4849

@@ -57,7 +58,7 @@ The main project files and directories are structured as follows:
5758

5859
## License
5960

60-
This project is licensed under the [MIT License](LICENSE).
61+
Wrapto is released under [MIT License](LICENSE).
6162

6263
---
6364

contracts/wpac.sol

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
77
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
88
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
99
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
10+
import "@openzeppelin/contracts/utils/math/Math.sol";
1011

1112
contract WrappedPAC is Initializable, OwnableUpgradeable, PausableUpgradeable, ERC20Upgradeable, UUPSUpgradeable {
1213
struct BridgeEvent {
@@ -15,7 +16,8 @@ contract WrappedPAC is Initializable, OwnableUpgradeable, PausableUpgradeable, E
1516
string destinationAddress;
1617
uint256 fee;
1718
}
18-
uint256 public constant FEE = 1_000_000_000; // 1wpac
19+
uint256 public constant MIN_FEE = 1_000_000_000; // 1wpac
20+
uint256 public constant MAX_FEE = 5_000_000_000; // 5wpac
1921
mapping(uint256 => BridgeEvent) public bridged;
2022
uint256 public counter;
2123
event Bridge(address indexed sender, uint256 amount, string destinationAddress, uint256 fee);
@@ -39,13 +41,30 @@ contract WrappedPAC is Initializable, OwnableUpgradeable, PausableUpgradeable, E
3941
_mint(to, amount);
4042
}
4143

44+
function getFee(uint256 amount) public pure returns (uint256) {
45+
uint256 f = Math.ceilDiv(amount, 200); // 0.5%
46+
47+
if (f <= MIN_FEE) {
48+
return MIN_FEE;
49+
}
50+
51+
if (f >= MAX_FEE) {
52+
return MAX_FEE;
53+
}
54+
55+
return f;
56+
}
57+
4258
function bridge(string memory destinationAddress, uint256 value) public whenNotPaused {
4359
require(value > (1 * 1e9), "Bridge: value is low.");
44-
_transfer(_msgSender(), address(this), FEE); //fee
60+
61+
_transfer(_msgSender(), address(this), getFee(value)); //fee
62+
4563
_burn(_msgSender(), value);
46-
emit Bridge(_msgSender(), value, destinationAddress, FEE);
64+
65+
emit Bridge(_msgSender(), value, destinationAddress, getFee(value));
4766
counter++;
48-
bridged[counter] = BridgeEvent(_msgSender(), value - FEE, destinationAddress, FEE);
67+
bridged[counter] = BridgeEvent(_msgSender(), value , destinationAddress, getFee(value));
4968
}
5069

5170
function adminBridge(string memory destinationAddress, uint256 value) public whenNotPaused onlyOwner {

package-lock.json

Lines changed: 2 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"packages/eslint-config"
99
],
1010
"scripts": {
11-
"node":"npx hardhat node",
11+
"node": "npx hardhat node",
1212
"compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile",
1313
"clean": "shx rm -rf ./artifacts ./cache ./coverage ./src/types ./coverage.json && yarn typechain",
1414
"lint:sol": "solhint --config ./.solhint.json --max-warnings 0 \"contracts/**/*.sol\"",
@@ -17,17 +17,17 @@
1717
"typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain"
1818
},
1919
"devDependencies": {
20-
"husky": "^8.0.3",
2120
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
22-
"hardhat": "^2.21.0"
21+
"hardhat": "^2.21.0",
22+
"husky": "^8.0.3"
2323
},
2424
"keywords": [],
2525
"author": "",
2626
"license": "MIT",
2727
"dependencies": {
28-
"@openzeppelin/hardhat-upgrades": "^3.0.5",
2928
"@openzeppelin/contracts": "^5.0.2",
3029
"@openzeppelin/contracts-upgradeable": "^4.7.3",
30+
"@openzeppelin/hardhat-upgrades": "^3.0.5",
3131
"dotenv": "^16.4.5"
3232
}
3333
}

test/bridge.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ethers, upgrades } from "hardhat"
22
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"
33
import { expect } from "chai"
44
import { decimal } from "../utils/decimal"
5+
import { getFee } from "./utils/fee"
56

67
export const shouldBehaveLikeBridge = async () => {
78
let wpac: any
@@ -42,10 +43,10 @@ export const shouldBehaveLikeBridge = async () => {
4243
expect(await wpac.balanceOf(bob.address)).to.be.equal(decimal(92))
4344
expect(b.destinationAddress).to.be.equal(pacAddr)
4445
expect(b.sender).to.be.equal(bob.address)
45-
expect(b.amount).to.be.equal(decimal(6))
46-
expect(b.fee).to.be.equal(decimal(1))
46+
expect(b.amount).to.be.equal(decimal(7))
47+
expect(b.fee).to.be.equal(getFee(7))
4748

48-
expect(await wpac.balanceOf(wpac.target)).to.be.equal(decimal(1)) //Fee
49+
expect(await wpac.balanceOf(wpac.target)).to.be.equal(getFee(7)) //Fee
4950
expect(await wpac.totalSupply()).to.be.equal(decimal(93)) //burn
5051
expect(await wpac.counter()).to.be.equal(1) //counter
5152
})

test/fee.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ethers, upgrades } from "hardhat"
2+
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"
3+
import { expect } from "chai"
4+
5+
export const shouldBehaveLikeFee = async () => {
6+
let wpac: any
7+
let owner: SignerWithAddress
8+
9+
before(async () => {
10+
const signers = await ethers.getSigners()
11+
owner = signers[0]
12+
const Factory = await ethers.getContractFactory("WrappedPAC")
13+
const WPAC = await upgrades.deployProxy(Factory, undefined, { initializer: "initialize" })
14+
wpac = await WPAC.waitForDeployment()
15+
})
16+
17+
it("should calculate correct fee", async () => {
18+
expect(await wpac.getFee(1_903_076_060_983)).to.be.equal(5_000_000_000)
19+
expect(await wpac.getFee(2_874_345_000)).to.be.equal(1_000_000_000)
20+
expect(await wpac.getFee(200e9)).to.be.equal(1e9)
21+
})
22+
}

test/init.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export const shouldBehaveLikeInitialize = async () => {
1717

1818
it("should init correct", async () => {
1919
expect(await wpac.owner()).to.be.equal(owner.address)
20-
expect(await wpac.FEE()).to.be.equal(decimal(1))
20+
expect(await wpac.MIN_FEE()).to.be.equal(decimal(1))
21+
expect(await wpac.MAX_FEE()).to.be.equal(decimal(5))
2122
expect(await wpac.counter()).to.be.equal(0)
2223
expect(await wpac.decimals()).to.be.equal(9)
2324
expect(await wpac.paused()).to.be.equal(false)

test/main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { shouldBehaveLikeAdminBridge } from "./adminBridge"
22
import { shouldBehaveLikeBridge } from "./bridge"
3+
import { shouldBehaveLikeFee } from "./fee"
34
import { shouldBehaveLikeInitialize } from "./init"
45
import { shouldBehaveLikeMint } from "./mint"
56
import { shouldBehaveLikeWithdrawFee } from "./withdrawFee"
@@ -23,4 +24,8 @@ describe("Wrapped PAC", function () {
2324
describe("WithdrawFee", async function () {
2425
shouldBehaveLikeWithdrawFee()
2526
})
27+
28+
describe("Fee", async function () {
29+
shouldBehaveLikeFee()
30+
})
2631
})

test/utils/fee.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { decimal } from "../../utils/decimal"
2+
3+
export function getFee(amount: number): bigint {
4+
const f = amount / 200
5+
6+
if (f <= decimal(1)) {
7+
return decimal(1)
8+
}
9+
10+
if (f >= decimal(5)) {
11+
return decimal(5)
12+
}
13+
14+
return decimal(f)
15+
}

0 commit comments

Comments
 (0)