Skip to content

Commit

Permalink
fix: fee calculation logic (#10)
Browse files Browse the repository at this point in the history
Co-authored-by: Kay <kehiiiiya@gmail.com>
  • Loading branch information
ZigBalthazar and kehiy authored Apr 10, 2024
1 parent 85f8e26 commit 32d3095
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ jobs:
run: npm install

- name: Run Hardhat tests
run: npx hardhat test
run: npm run test
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Welcome to the repository for Wrapped PAC (WPAC) token. WPAC is a wrapped token

## Project Overview

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.
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.

## Getting Started

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

## Contract Overview

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.
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.


## Project Structure

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

## License

This project is licensed under the [MIT License](LICENSE).
Wrapto is released under [MIT License](LICENSE).

---

Expand Down
27 changes: 23 additions & 4 deletions contracts/wpac.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

contract WrappedPAC is Initializable, OwnableUpgradeable, PausableUpgradeable, ERC20Upgradeable, UUPSUpgradeable {
struct BridgeEvent {
Expand All @@ -15,7 +16,8 @@ contract WrappedPAC is Initializable, OwnableUpgradeable, PausableUpgradeable, E
string destinationAddress;
uint256 fee;
}
uint256 public constant FEE = 1_000_000_000; // 1wpac
uint256 public constant MIN_FEE = 1_000_000_000; // 1wpac
uint256 public constant MAX_FEE = 5_000_000_000; // 5wpac
mapping(uint256 => BridgeEvent) public bridged;
uint256 public counter;
event Bridge(address indexed sender, uint256 amount, string destinationAddress, uint256 fee);
Expand All @@ -39,13 +41,30 @@ contract WrappedPAC is Initializable, OwnableUpgradeable, PausableUpgradeable, E
_mint(to, amount);
}

function getFee(uint256 amount) public pure returns (uint256) {
uint256 f = Math.ceilDiv(amount, 200); // 0.5%

if (f <= MIN_FEE) {
return MIN_FEE;
}

if (f >= MAX_FEE) {
return MAX_FEE;
}

return f;
}

function bridge(string memory destinationAddress, uint256 value) public whenNotPaused {
require(value > (1 * 1e9), "Bridge: value is low.");
_transfer(_msgSender(), address(this), FEE); //fee

_transfer(_msgSender(), address(this), getFee(value)); //fee

_burn(_msgSender(), value);
emit Bridge(_msgSender(), value, destinationAddress, FEE);

emit Bridge(_msgSender(), value, destinationAddress, getFee(value));
counter++;
bridged[counter] = BridgeEvent(_msgSender(), value - FEE, destinationAddress, FEE);
bridged[counter] = BridgeEvent(_msgSender(), value , destinationAddress, getFee(value));
}

function adminBridge(string memory destinationAddress, uint256 value) public whenNotPaused onlyOwner {
Expand Down
7 changes: 2 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"packages/eslint-config"
],
"scripts": {
"node":"npx hardhat node",
"node": "npx hardhat node",
"compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile",
"clean": "shx rm -rf ./artifacts ./cache ./coverage ./src/types ./coverage.json && yarn typechain",
"lint:sol": "solhint --config ./.solhint.json --max-warnings 0 \"contracts/**/*.sol\"",
Expand All @@ -17,17 +17,17 @@
"typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain"
},
"devDependencies": {
"husky": "^8.0.3",
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"hardhat": "^2.21.0"
"hardhat": "^2.21.0",
"husky": "^8.0.3"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"@openzeppelin/hardhat-upgrades": "^3.0.5",
"@openzeppelin/contracts": "^5.0.2",
"@openzeppelin/contracts-upgradeable": "^4.7.3",
"@openzeppelin/hardhat-upgrades": "^3.0.5",
"dotenv": "^16.4.5"
}
}
7 changes: 4 additions & 3 deletions test/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ethers, upgrades } from "hardhat"
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"
import { expect } from "chai"
import { decimal } from "../utils/decimal"
import { getFee } from "./utils/fee"

export const shouldBehaveLikeBridge = async () => {
let wpac: any
Expand Down Expand Up @@ -42,10 +43,10 @@ export const shouldBehaveLikeBridge = async () => {
expect(await wpac.balanceOf(bob.address)).to.be.equal(decimal(92))
expect(b.destinationAddress).to.be.equal(pacAddr)
expect(b.sender).to.be.equal(bob.address)
expect(b.amount).to.be.equal(decimal(6))
expect(b.fee).to.be.equal(decimal(1))
expect(b.amount).to.be.equal(decimal(7))
expect(b.fee).to.be.equal(getFee(7))

expect(await wpac.balanceOf(wpac.target)).to.be.equal(decimal(1)) //Fee
expect(await wpac.balanceOf(wpac.target)).to.be.equal(getFee(7)) //Fee
expect(await wpac.totalSupply()).to.be.equal(decimal(93)) //burn
expect(await wpac.counter()).to.be.equal(1) //counter
})
Expand Down
22 changes: 22 additions & 0 deletions test/fee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ethers, upgrades } from "hardhat"
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"
import { expect } from "chai"

export const shouldBehaveLikeFee = async () => {
let wpac: any
let owner: SignerWithAddress

before(async () => {
const signers = await ethers.getSigners()
owner = signers[0]
const Factory = await ethers.getContractFactory("WrappedPAC")
const WPAC = await upgrades.deployProxy(Factory, undefined, { initializer: "initialize" })
wpac = await WPAC.waitForDeployment()
})

it("should calculate correct fee", async () => {
expect(await wpac.getFee(1_903_076_060_983)).to.be.equal(5_000_000_000)
expect(await wpac.getFee(2_874_345_000)).to.be.equal(1_000_000_000)
expect(await wpac.getFee(200e9)).to.be.equal(1e9)
})
}
3 changes: 2 additions & 1 deletion test/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export const shouldBehaveLikeInitialize = async () => {

it("should init correct", async () => {
expect(await wpac.owner()).to.be.equal(owner.address)
expect(await wpac.FEE()).to.be.equal(decimal(1))
expect(await wpac.MIN_FEE()).to.be.equal(decimal(1))
expect(await wpac.MAX_FEE()).to.be.equal(decimal(5))
expect(await wpac.counter()).to.be.equal(0)
expect(await wpac.decimals()).to.be.equal(9)
expect(await wpac.paused()).to.be.equal(false)
Expand Down
5 changes: 5 additions & 0 deletions test/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { shouldBehaveLikeAdminBridge } from "./adminBridge"
import { shouldBehaveLikeBridge } from "./bridge"
import { shouldBehaveLikeFee } from "./fee"
import { shouldBehaveLikeInitialize } from "./init"
import { shouldBehaveLikeMint } from "./mint"
import { shouldBehaveLikeWithdrawFee } from "./withdrawFee"
Expand All @@ -23,4 +24,8 @@ describe("Wrapped PAC", function () {
describe("WithdrawFee", async function () {
shouldBehaveLikeWithdrawFee()
})

describe("Fee", async function () {
shouldBehaveLikeFee()
})
})
15 changes: 15 additions & 0 deletions test/utils/fee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { decimal } from "../../utils/decimal"

export function getFee(amount: number): bigint {
const f = amount / 200

if (f <= decimal(1)) {
return decimal(1)
}

if (f >= decimal(5)) {
return decimal(5)
}

return decimal(f)
}

0 comments on commit 32d3095

Please sign in to comment.