Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion GOVERNANCE_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ We will:
- `HuffyTimelock`
- `HuffyGovernor` (wired to the Timelock and HTK)
- `ParameterStore` (owned by Timelock)
- `PairWhitelist` (owned by Timelock)
- `PairWhitelist` (managed directly by DAO admin)
- `HTK` Votes token address (ERC20Votes-compatible) with voting power delegated

If you need to deploy the stack, see `script/Governor.s.sol` for a reference deployment flow.
Expand Down
26 changes: 16 additions & 10 deletions INTEGRATION_TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ RPC_URL=127.0.0.1:8545
USDC_TOKEN_ADDRESS=0x5bf5b11053e734690269C6B9D438F8C9d48F528A
HTK_TOKEN_ADDRESS=0x3347B4d90ebe72BeFb30444C9966B2B990aE9FcB
SAUCERSWAP_ROUTER=0x3aAde2dCD2Df6a8cAc689EE797591b2913658659
SWAP_ADAPTER_ADDRESS=0xSwapAdapter
MOCK_DAO_ADDRESS=0x1f10F3Ba7ACB61b2F50B9d6DdCf91a6f787C0E82
DAO_ADMIN_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
RELAY_ADDRESS=0xb9bEECD1A582768711dE1EE7B0A1d582D9d72a6C
Expand All @@ -31,6 +32,11 @@ MAX_SLIPPAGE_BPS=500 # 5%
TRADE_COOLDOWN_SEC=60 # 60 seconds

DEADLINE=1918370747

# Adapter paths (bytes-encoded routes for the swap adapter)
USDC_TO_HTK_PATH=0xYourEncodedPathHere
HTK_TO_USDC_PATH=0xYourReversePathHere
USDC_TO_USDC_PATH=0xLoopbackPathForTesting
```

```shell
Expand Down Expand Up @@ -225,7 +231,7 @@ cast call $TREASURY_ADDRESS "getBalance(address)" $HTK_TOKEN_ADDRESS --rpc-url $
# Step 3: Propose (relay) and Execute (treasury) swap 1000 USDC (6 decimals) -> HTK (18 decimals)
# amountIn = 1000 * 10^6 = 1000000000 (1000 USDC)
# amountOutMin = 1900 * 10^18 = 1900000000000000000000 (1900 HTK with 5% slippage)
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS $USDC_TO_HTK_PATH 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```

```shell
Expand Down Expand Up @@ -255,7 +261,7 @@ cast call $TREASURY_ADDRESS "getBalance(address)" $HTK_TOKEN_ADDRESS --rpc-url $
# Step 2: Execute buyback-and-burn 500 USDC -> HTK (burn)
# amountIn = 500 * 10^6 = 500000000 (500 USDC)
# amountOutMin = 950 * 10^18 = 950000000000000000000 (950 HTK with 5% slippage)
cast send $RELAY_ADDRESS "proposeBuybackAndBurn(address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS 500000000 950000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeBuybackAndBurn(address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $USDC_TO_HTK_PATH 500000000 950000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```
```shell
# Step 3: Check balances after buyback (HTK should be burned – sent to 0xdead)
Expand Down Expand Up @@ -283,12 +289,12 @@ cast call $RELAY_ADDRESS "getMaxAllowedTradeAmount(address)" $HTK_TOKEN_ADDRESS
# Option A (respect 10% cap): swap 200 HTK
# amountIn = 200 * 10^18 = 200000000000000000000 (200 HTK)
# With rate 1 HTK = 0.5 USDC, expected = 100 USDC; with 5% slippage, min = 95 USDC
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $HTK_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS 200000000000000000000 95000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $HTK_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS $HTK_TO_USDC_PATH 200000000000000000000 95000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY

# Option B (if you want to trade 1000 HTK): temporarily raise the cap via DAO to 50%
# cast send $RELAY_ADDRESS "setMaxTradeBps(uint256)" 5000 --rpc-url $RPC_URL --private-key $PRIVATE_KEY
# Then you can use the original 1000 HTK example:
# cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $HTK_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS 1000000000000000000000 475000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
# cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $HTK_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS $HTK_TO_USDC_PATH 1000000000000000000000 475000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY

# Check balances
echo "HTK balance:"
Expand Down Expand Up @@ -395,7 +401,7 @@ cast send $PAIR_WHITELIST_ADDRESS "removePair(address,address)" $USDC_TOKEN_ADDR
cast call $PAIR_WHITELIST_ADDRESS "isPairWhitelisted(address,address)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS --rpc-url $RPC_URL

# Attempt swap on blacklisted pair (should fail)
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS $USDC_TO_HTK_PATH 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY

# Restore pair to whitelist
cast send $PAIR_WHITELIST_ADDRESS "addPair(address,address)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS --rpc-url $RPC_URL --private-key $PRIVATE_KEY
Expand All @@ -419,22 +425,22 @@ cast send $PAIR_WHITELIST_ADDRESS "addPair(address,address)" $HTK_TOKEN_ADDRESS
```shell
# Test 1: Attempt trade without TRADER_ROLE (should fail)
UNAUTHORIZED_USER=0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS $USDC_TO_HTK_PATH 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
# Expected: AccessControlUnauthorizedAccount

# Test 2: Attempt swap on non-whitelisted pair
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS 1000000000 1000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS $USDC_TO_USDC_PATH 1000000000 1000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
# Expected: Relay: Pair not whitelisted

# Test 3: Attempt trade before cooldown
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS $USDC_TO_HTK_PATH 1000000000 1900000000000000000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
# Immediately after:
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $HTK_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS 1000000000000000000000 475000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $HTK_TOKEN_ADDRESS $USDC_TOKEN_ADDRESS $HTK_TO_USDC_PATH 1000000000000000000000 475000000 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
# Expected: Relay: Cooldown active

# Test 4: Attempt to exceed maxTradeBps
# If Treasury has 100,000 USDC, max trade = 10% = 10,000 USDC
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS 20000000000 1 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS $USDC_TO_HTK_PATH 20000000000 1 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
# Expected: Relay: Trade amount exceeds limit
```

Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,29 @@ forge script script/SaucerswapMock.s.sol:SaucerswapMock \
```
source .env
```
`HTK_TOKEN_ADDRESS, SAUCERSWAP_ROUTER, DAO_ADMIN_ADDRESS, RELAY_ADDRESS`
`SAUCERSWAP_ROUTER, WHBAR_TOKEN_ADDRESS`
```bash
forge script script/SwapRouterProxyHedera.s.sol:DeploySwapRouterProxyHedera \
--rpc-url $HEDERA_RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast
```
---
```
source .env
```
`SWAP_ROUTER_PROXY_ADDRESS`
```bash
forge script script/SaucerswapAdapter.s.sol:DeploySaucerswapAdapter \
--rpc-url $HEDERA_RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast
```
---
```
source .env
```
`SWAP_ADAPTER_ADDRESS`
```bash
forge script script/Treasury.s.sol:DeployTreasury \
--rpc-url $HEDERA_RPC_URL \
Expand Down
8 changes: 6 additions & 2 deletions RELAY_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,10 @@ Only authorized traders can submit trades:

```bash
# From trader account (HuffyPuppet)
cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)" \
cast send $RELAY_ADDRESS "proposeSwap(address,address,bytes,uint256,uint256,uint256)" \
$USDC_TOKEN_ADDRESS \
$USDT_TOKEN_ADDRESS \
$USDC_TO_USDT_PATH \
100000000 \
95000000 \
$DEADLINE \
Expand All @@ -155,6 +156,7 @@ cast send $RELAY_ADDRESS "proposeSwap(address,address,uint256,uint256,uint256)"
Parameters:
- tokenIn: Input token address
- tokenOut: Output token address
- path: Adapter-specific encoded bytes path describing the swap route
- amountIn: Amount to swap (e.g., 100 USDC = 100000000 with 6 decimals)
- minAmountOut: Minimum expected output (accounting for slippage)
- deadline: UNIX timestamp
Expand All @@ -163,8 +165,9 @@ Parameters:

```bash
# From trader account
cast send $RELAY_ADDRESS "proposeBuybackAndBurn(address,uint256,uint256,uint256)" \
cast send $RELAY_ADDRESS "proposeBuybackAndBurn(address,bytes,uint256,uint256,uint256)" \
$USDC_TOKEN_ADDRESS \
$USDC_TO_HTK_PATH \
100000000 \
190000000000000000000 \
$DEADLINE \
Expand All @@ -174,6 +177,7 @@ cast send $RELAY_ADDRESS "proposeBuybackAndBurn(address,uint256,uint256,uint256)

Parameters:
- tokenIn: Input token address (e.g., USDC)
- path: Adapter-specific bytes path for the trade
- amountIn: Amount to swap (e.g., 100 USDC)
- minAmountOut: Minimum HTK expected (e.g., 190 HTK with 18 decimals)
- deadline: UNIX timestamp
Expand Down
22 changes: 14 additions & 8 deletions TREASURY_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
This project includes a Treasury contract that can hold tokens, execute buyback-and-burn operations via the Saucerswap router, perform generic token swaps, and allow DAO-controlled withdrawals.

Important context from the code:
- Treasury constructor: `Treasury(address htkToken, address saucerswapRouter, address daoAdmin, address relay)`
- Treasury constructor: `Treasury(address htkToken, address swapAdapter, address daoAdmin, address relay)`
- Roles:
- `DEFAULT_ADMIN_ROLE` and `DAO_ROLE` are given to `daoAdmin` at deploy time.
- `RELAY_ROLE` is given to `relay` at deploy time; only the relay can call swap and buyback.
- Router interface: uses `swapExactTokensForTokens` as per Saucerswap.
- Swaps route directly through an `ISwapAdapter` set on Treasury; the DAO can update the adapter via `setAdapter(address)`.
- Mocks: `MockERC20`, `MockSaucerswapRouter` (with settable exchange rates), `MockDAO` (acts as DAO admin), and `MockRelay` (to invoke Treasury methods).

To change adapters in production, the DAO calls `setAdapter(address)` on Treasury:
```
cast send $TREASURY_ADDRESS "setAdapter(address)" $NEW_ADAPTER --rpc-url $RPC_URL --private-key $DAO_ADMIN_PRIVATE_KEY
```

Important script roles:
- script/DeployMocks.s.sol: Deploys a full testing environment on testnet, including mocks AND a Treasury instance wired to the mock router. Use this to prepare contracts and addresses for end-to-end testing.
- script/Treasury.s.sol: Production deployment script for the real Treasury on testnet/mainnet with your real token/router/admin/relay settings.
Expand Down Expand Up @@ -119,30 +124,31 @@ Only an account with `RELAY_ROLE` can call `executeBuybackAndBurn`. You may invo

Direct call (caller must have `RELAY_ROLE`):
```
# Swap 100 USDC for HTK and burn the HTK received
cast send $TREASURY_ADDRESS "executeBuybackAndBurn(address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS 100000000 0 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
# Swap 100 USDC for HTK and burn the HTK received (provide an encoded swap path)
cast send $TREASURY_ADDRESS "executeBuybackAndBurn(address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $USDC_TO_HTK_PATH 100000000 0 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```
Via MockRelay (recommended during testing):
```
cast send $RELAY "executeBuybackAndBurn(address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS 100000000 0 DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY "executeBuybackAndBurn(address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $USDC_TO_HTK_PATH 100000000 0 DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```
Notes:
- Ensure the Treasury holds enough `tokenIn` (e.g., USDC) before calling.
- `$USDC_TO_HTK_PATH` should contain the adapter-specific bytes-encoded path for the swap route.
- `amountOutMin` can be set to 0 for testing, or a slippage-protected minimum.
- The burn is implemented by transferring HTK to the `0xdead` address and emits `Burned(amount, initiator, timestamp)`.

### D) Generic trade-swap without burning (Relay only)

Use `executeSwap(tokenIn, tokenOut, amountIn, amountOutMin, deadline)` to swap and keep proceeds in the Treasury.
Use `executeSwap(tokenIn, tokenOut, path, amountIn, amountOutMin, deadline)` to swap and keep proceeds in the Treasury.

Direct call on Treasury (requires `RELAY_ROLE`):
```
# Example: swap USDC -> HTK
cast send $TREASURY_ADDRESS "executeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS 100000000 0 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $TREASURY_ADDRESS "executeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS $USDC_TO_HTK_PATH 100000000 0 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```
Via MockRelay:
```
cast send $RELAY_ADDRESS "executeSwap(address,address,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS 100000000 0 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
cast send $RELAY_ADDRESS "executeSwap(address,address,bytes,uint256,uint256,uint256)" $USDC_TOKEN_ADDRESS $HTK_TOKEN_ADDRESS $USDC_TO_HTK_PATH 100000000 0 $DEADLINE --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```
Check the Treasury's balances after the swap:
```
Expand Down
4 changes: 2 additions & 2 deletions script/DAOmock.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ contract MockDAOScript is Script {
MockDAO mockDao = new MockDAO();
console.log("Mock DAO:", address(mockDao));

address treasuryAddress = vm.envAddress("TREASURY_ADDRESS");
address payable treasuryAddress = payable(vm.envAddress("TREASURY_ADDRESS"));
Treasury treasury = Treasury(treasuryAddress);

treasury.grantRole(treasury.DEFAULT_ADMIN_ROLE(), address(mockDao));

address relay = vm.envOr("RELAY_ADDRESS", msg.sender);

mockDao.setTreasury(address(treasury));
mockDao.setTreasury(treasuryAddress);
mockDao.updateRelay(msg.sender, relay);

vm.stopBroadcast();
Expand Down
105 changes: 0 additions & 105 deletions script/Governor.s.sol

This file was deleted.

2 changes: 1 addition & 1 deletion script/Relay.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {Relay} from "../src/Relay.sol";
contract DeployRelay is Script {
function run() external {
address pairWhitelist = vm.envAddress("PAIR_WHITELIST_ADDRESS");
address treasury = vm.envAddress("TREASURY_ADDRESS");
address payable treasury = payable(vm.envAddress("TREASURY_ADDRESS"));
address saucerswapRouter = vm.envAddress("SAUCERSWAP_ROUTER");
address daoAdmin = vm.envOr("DAO_ADMIN_ADDRESS", msg.sender);

Expand Down
Loading