Skip to content
Open
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
147 changes: 147 additions & 0 deletions test/BankPrecompile.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";

/// @title IBankModule
/// @notice Interface for the Injective Bank precompile at address 0x64
interface IBankModule {
/// @notice Mint tokens to a recipient
function mint(address recipient, uint256 amount) external payable returns (bool);

/// @notice Burn tokens from an account
function burn(address account, uint256 amount) external payable returns (bool);

/// @notice Get balance of an account for a token
function balanceOf(address token, address account) external view returns (uint256);

/// @notice Transfer tokens between addresses
function transfer(address from, address to, uint256 amount) external payable returns (bool);

/// @notice Get total supply of a token
function totalSupply(address token) external view returns (uint256);

/// @notice Get metadata of a token
function metadata(address token) external view returns (string memory name, string memory symbol, uint8 decimals);

/// @notice Set metadata for a token
function setMetadata(string memory name, string memory symbol, uint8 decimals) external payable returns (bool);
}

contract BankPrecompileTest is Test {
IBankModule bank = IBankModule(address(0x64));

address token = address(0x1);
address alice = address(0x100);
address bob = address(0x200);
address charlie = address(0x300);

// Comprehensive test script that tells a story
function run() public {
console.log("=== Injective Bank Precompile Integration Test ===\n");

// Setup: Set token metadata
console.log("1. Setting up token metadata...");
vm.prank(token);
bool success = bank.setMetadata("Test Token", "TEST", 18);
assertTrue(success, "Failed to set metadata");

(string memory name, string memory symbol, uint8 decimals) = bank.metadata(token);
console.log(" Token created: %s (%s) with %s decimals", name, symbol, decimals);
assertEq(name, "Test Token");
assertEq(symbol, "TEST");
assertEq(decimals, 18);

// Initial state checks
console.log("\n2. Checking initial balances (should be zero)...");
assertEq(bank.balanceOf(token, alice), 0, "Alice should start with 0");
assertEq(bank.balanceOf(token, bob), 0, "Bob should start with 0");
assertEq(bank.totalSupply(token), 0, "Total supply should be 0");
console.log(" All balances start at zero [OK]");

// Mint tokens to Alice
console.log("\n3. Minting 10,000 tokens to Alice...");
vm.prank(token);
success = bank.mint(alice, 10000);
assertTrue(success, "Failed to mint to Alice");

uint256 aliceBalance = bank.balanceOf(token, alice);
uint256 supply = bank.totalSupply(token);
console.log(" Alice balance: %s", aliceBalance);
console.log(" Total supply: %s", supply);
assertEq(aliceBalance, 10000, "Alice should have 10000");
assertEq(supply, 10000, "Supply should be 10000");

// Mint tokens to Bob
console.log("\n4. Minting 5,000 tokens to Bob...");
vm.prank(token);
success = bank.mint(bob, 5000);
assertTrue(success, "Failed to mint to Bob");

uint256 bobBalance = bank.balanceOf(token, bob);
supply = bank.totalSupply(token);
console.log(" Bob balance: %s", bobBalance);
console.log(" Total supply: %s", supply);
assertEq(bobBalance, 5000, "Bob should have 5000");
assertEq(supply, 15000, "Supply should be 15000");

// Transfer from Alice to Charlie
console.log("\n5. Alice transfers 3,000 tokens to Charlie...");
vm.prank(token);
success = bank.transfer(alice, charlie, 3000);
assertTrue(success, "Failed to transfer");

aliceBalance = bank.balanceOf(token, alice);
uint256 charlieBalance = bank.balanceOf(token, charlie);
supply = bank.totalSupply(token);
console.log(" Alice balance: %s", aliceBalance);
console.log(" Charlie balance: %s", charlieBalance);
console.log(" Total supply: %s (unchanged)", supply);
assertEq(aliceBalance, 7000, "Alice should have 7000");
assertEq(charlieBalance, 3000, "Charlie should have 3000");
assertEq(supply, 15000, "Supply should still be 15000");

// Burn tokens from Bob
console.log("\n6. Burning 2,000 tokens from Bob...");
vm.prank(token);
success = bank.burn(bob, 2000);
assertTrue(success, "Failed to burn");

bobBalance = bank.balanceOf(token, bob);
supply = bank.totalSupply(token);
console.log(" Bob balance: %s", bobBalance);
console.log(" Total supply: %s", supply);
assertEq(bobBalance, 3000, "Bob should have 3000");
assertEq(supply, 13000, "Supply should be 13000");

// Transfer from Bob to Alice
console.log("\n7. Bob transfers 1,000 tokens to Alice...");
vm.prank(token);
success = bank.transfer(bob, alice, 1000);
assertTrue(success, "Failed to transfer");

aliceBalance = bank.balanceOf(token, alice);
bobBalance = bank.balanceOf(token, bob);
console.log(" Alice balance: %s", aliceBalance);
console.log(" Bob balance: %s", bobBalance);
assertEq(aliceBalance, 8000, "Alice should have 8000");
assertEq(bobBalance, 2000, "Bob should have 2000");

// Final state summary
console.log("\n8. Final state summary:");
console.log(" ========================");
console.log(" Alice: %s tokens", bank.balanceOf(token, alice));
console.log(" Bob: %s tokens", bank.balanceOf(token, bob));
console.log(" Charlie: %s tokens", bank.balanceOf(token, charlie));
console.log(" ========================");
console.log(" Total: %s tokens", bank.totalSupply(token));

// Verify final balances
assertEq(bank.balanceOf(token, alice), 8000);
assertEq(bank.balanceOf(token, bob), 2000);
assertEq(bank.balanceOf(token, charlie), 3000);
assertEq(bank.totalSupply(token), 13000);

console.log("\n=== All operations completed successfully! ===");
}
}
87 changes: 87 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Bank Precompile Tests

This directory contains tests for the Injective Bank precompile implementation in Foundry.

## BankPrecompile.t.sol

Comprehensive integration test for the Bank precompile at address `0x64`.

### Prerequisites

**This test requires the Injective Foundry fork.** You must build and install Foundry from:
```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language identifiers to fenced code blocks.

Markdown linters expect fenced code blocks to specify a language for proper syntax highlighting.

Apply this diff:

-```
+```bash
 https://github.com/InjectiveLabs/foundry/tree/CP-698/complete-bank-precompile

(and similarly for line 48)

- +text
=== Injective Bank Precompile Integration Test ===

Also applies to: 48-48

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

12-12: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In test/README.md around lines 12 and 48, the fenced code blocks are missing
language identifiers; update the opening fences accordingly: change the fence at
line 12 to ```bash for the GitHub URL block and change the fence at line 48 to
```text for the "=== Injective Bank Precompile Integration Test ===" block so
markdown linters and syntax highlighting recognize the languages.

https://github.com/InjectiveLabs/foundry/tree/CP-698/complete-bank-precompile
```

To build and install:
```bash
git clone https://github.com/InjectiveLabs/foundry.git
cd foundry
git checkout CP-698/complete-bank-precompile
cargo build --release --target aarch64-apple-darwin
cp target/aarch64-apple-darwin/release/forge ~/.foundry/bin/forge
```
Comment on lines +16 to +23
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make build instructions platform-agnostic.

The build command hardcodes --target aarch64-apple-darwin (macOS ARM), which won't work on Linux, Windows, or Intel-based systems. Consider providing generic instructions or documenting alternatives for other platforms.

Apply this diff to make the instructions more portable:

 To build and install:
 ```bash
 git clone https://github.com/InjectiveLabs/foundry.git
 cd foundry
 git checkout CP-698/complete-bank-precompile
-cargo build --release --target aarch64-apple-darwin
-cp target/aarch64-apple-darwin/release/forge ~/.foundry/bin/forge
+cargo build --release
+# On Unix-like systems:
+cp target/release/forge ~/.foundry/bin/forge
+# On Windows:
+# copy target\release\forge.exe %USERPROFILE%\.foundry\bin\forge.exe

<details>
<summary>🤖 Prompt for AI Agents</summary>

test/README.md around lines 16 to 23: the build instructions hardcode the macOS
ARM target (--target aarch64-apple-darwin) which is not portable; change to a
generic cargo build --release and document platform-specific install commands
(e.g., cp target/release/forge ~/.foundry/bin/forge for Unix-like systems and
copy target\release\forge.exe %USERPROFILE%.foundry\bin\forge.exe for Windows)
so users on Linux, Intel macs, and Windows have correct steps.


</details>

<!-- This is an auto-generated comment by CodeRabbit -->


The standard Foundry release does **not** include the Bank precompile implementation.

### Running the Test

```bash
forge script test/BankPrecompile.t.sol:BankPrecompileTest --chain-id 1776
```

**Important**: Use `forge script` with `--chain-id 1776` instead of `forge test`. The chain ID activates Injective network features and properly injects the precompile. The standard `forge test` command doesn't inject precompiles even with the chain-id flag.

### Test Scenario

The test runs a comprehensive story exercising all 7 precompile methods:

1. **Setup** - Set token metadata ("Test Token", "TEST", 18 decimals)
2. **Mint** - Mint 10,000 tokens to Alice and 5,000 to Bob
3. **Transfer** - Alice transfers 3,000 tokens to Charlie
4. **Burn** - Burn 2,000 tokens from Bob
5. **Transfer** - Bob transfers 1,000 tokens to Alice
6. **Verify** - Final state: Alice=8,000, Bob=2,000, Charlie=3,000, Total=13,000

### Expected Output

```
=== Injective Bank Precompile Integration Test ===

1. Setting up token metadata...
Token created: Test Token (TEST) with 18 decimals

2. Checking initial balances (should be zero)...
All balances start at zero [OK]

3. Minting 10,000 tokens to Alice...
Alice balance: 10000
Total supply: 10000

4. Minting 5,000 tokens to Bob...
Bob balance: 5000
Total supply: 15000

5. Alice transfers 3,000 tokens to Charlie...
Alice balance: 7000
Charlie balance: 3000
Total supply: 15000 (unchanged)

6. Burning 2,000 tokens from Bob...
Bob balance: 3000
Total supply: 13000

7. Bob transfers 1,000 tokens to Alice...
Alice balance: 8000
Bob balance: 2000

8. Final state summary:
========================
Alice: 8000 tokens
Bob: 2000 tokens
Charlie: 3000 tokens
========================
Total: 13000 tokens

=== All operations completed successfully! ===
```