Skip to content

Commit 881715a

Browse files
authored
Deploy ISMP contracts on Pharos Atlantic testnet (#759)
1 parent b1bcafa commit 881715a

File tree

24 files changed

+360
-192
lines changed

24 files changed

+360
-192
lines changed

Cargo.lock

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/content/developers/evm/contract-addresses/testnet.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,20 @@ The current testnet environment for the Hyperbridge network.
153153
| `StateMachine` | `EVM-3448148188` |
154154

155155

156+
### Pharos Atlantic
157+
158+
| `IsmpHost` | [`0xED54E9b64043c389173316B6351Bd25491060eA8`](https://pharos-testnet.socialscan.io/address/0xED54E9b64043c389173316B6351Bd25491060eA8) |
159+
|:------------|:-----|
160+
| `HandlerV1` | [`0x8B37747BBF8c8485026B9Dc2f8Fb177096EF574f`](https://pharos-testnet.socialscan.io/address/0x8B37747BBF8c8485026B9Dc2f8Fb177096EF574f) |
161+
| `PingModule` | [`0xBB3dFCcBAE0ae8F00320E46719c342fd69f5516C`](https://pharos-testnet.socialscan.io/address/0xBB3dFCcBAE0ae8F00320E46719c342fd69f5516C) |
162+
| `TokenGateway` | [`0x451bDd8273839AD0Ec7F4Fa798E8B3DABb223fD8`](https://pharos-testnet.socialscan.io/address/0x451bDd8273839AD0Ec7F4Fa798E8B3DABb223fD8) |
163+
| `IntentGateway` | [`0xb8039832c6c9266F928d038eA49A8a169300C670`](https://pharos-testnet.socialscan.io/address/0xb8039832c6c9266F928d038eA49A8a169300C670) |
164+
| `CallDispatcher` | [`0x7CBe6D93d04A2e736Fa6cA153099d78da2aCaA0E`](https://pharos-testnet.socialscan.io/address/0x7CBe6D93d04A2e736Fa6cA153099d78da2aCaA0E) |
165+
| `TokenFaucet` | [`0xD2cFb5b876d6D0dc17cbb6f09Bc2415F2d8a6908`](https://pharos-testnet.socialscan.io/address/0xD2cFb5b876d6D0dc17cbb6f09Bc2415F2d8a6908) |
166+
| `FeeToken (USD.h)` | [`0xeaB7572c5506978C9A4Ff0A0BA5A1291e327B0B8`](https://pharos-testnet.socialscan.io/address/0xeaB7572c5506978C9A4Ff0A0BA5A1291e327B0B8) |
167+
| `ConsensusStateId` | `PHAR` |
168+
| `StateMachine` | `EVM-688689` |
169+
156170
## Gargantua V2 (Paseo) (Deprecated)
157171

158172
Deprecated testnet environment for Gargantua V2 (Paseo).

evm/config.testnet.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,23 @@ FEE_TOKEN = "0x1452D37b4B0d28dd2fa77b2F0bC784274db7b3F7"
8585
is_mainnet = false
8686
7702 = false
8787

88+
[688689]
89+
endpoint_url = "${PHAROS_ATLANTIC_RPC}"
90+
91+
[688689.address]
92+
HOST = "0xED54E9b64043c389173316B6351Bd25491060eA8"
93+
PING = "0xBB3dFCcBAE0ae8F00320E46719c342fd69f5516C"
94+
TOKEN_FAUCET = "0xD2cFb5b876d6D0dc17cbb6f09Bc2415F2d8a6908"
95+
HANDLER = "0x8B37747BBF8c8485026B9Dc2f8Fb177096EF574f"
96+
FEE_TOKEN = "0xeaB7572c5506978C9A4Ff0A0BA5A1291e327B0B8"
97+
CALL_DISPATCHER = "0x7CBe6D93d04A2e736Fa6cA153099d78da2aCaA0E"
98+
TOKEN_GATEWAY = "0x451bDd8273839AD0Ec7F4Fa798E8B3DABb223fD8"
99+
INTENT_GATEWAY = "0xb8039832c6c9266F928d038eA49A8a169300C670"
100+
101+
[688689.bool]
102+
is_mainnet = false
103+
7702 = false
104+
88105
[420420417]
89106
endpoint_url = "${POLKADOT_TESTNET_URL}"
90107

evm/foundry.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ bsc-testnet = "${BSC_TESTNET_RPC_URL}"
2525
gnosis-chiado = "${GNOSIS_CHIADO_RPC_URL}"
2626
sei-testnet = "${SEI_TESTNET_RPC_URL}"
2727
polkadot-testnet = "${POLKADOT_TESTNET_URL}"
28+
pharos-testnet = "${PHAROS_ATLANTIC_RPC}"
2829

2930
# mainnet
3031
ethereum = "${ETHEREUM_RPC_URL}"
@@ -50,6 +51,7 @@ bsc-testnet = { chain = 97, key="${ETHEREUM_ETHERSCAN_API_KEY}", url = "https://
5051
gnosis-chiado = { chain = 10200, key = "${GNOSIS_BLOCKSCOUT_API_KEY}",url = "https://gnosis-chiado.blockscout.com/api" }
5152
sei-testnet = { chain = 1328, key="${ETHEREUM_ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api" }
5253
polkadot-testnet = { chain = 420420417, key="${ROUTESCAN_API_KEY}", url = "https://api.routescan.io/v2/network/testnet/evm/420420417/etherscan/api" }
54+
pharos-testnet = { chain = 688689, key="${PHAROS_EXPLORER_API_KEY}", url = "${PHAROS_EXPLORER_API_URL}" }
5355

5456
# mainnet
5557
ethereum = { chain = 1, key="${ETHEREUM_ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=1" }

evm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"dependencies": {
1515
"@hyperbridge/core": "^1.6.0",
1616
"@openzeppelin/contracts": "^5.4.0",
17-
"@polytope-labs/solidity-merkle-trees": "^0.4.0",
17+
"@polytope-labs/solidity-merkle-trees": "0.4.0",
1818
"@uniswap/swap-router-contracts": "^1.3.1",
1919
"@uniswap/universal-router": "github:Uniswap/universal-router",
2020
"@uniswap/v2-periphery": "^1.1.0-beta.0",

evm/pnpm-lock.yaml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

evm/script/DeployIsmp.s.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {PingModule} from "../src/utils/PingModule.sol";
2727
import {BscHost} from "../src/hosts/Bsc.sol";
2828
import {PolygonHost} from "../src/hosts/Polygon.sol";
2929
import {PolkadotHost} from "../src/hosts/Polkadot.sol";
30+
import {PharosHost} from "../src/hosts/Pharos.sol";
3031

3132
import {SP1Verifier} from "@sp1-contracts/v5.0.0/SP1VerifierGroth16.sol";
3233
import {SP1Beefy} from "../src/consensus/SP1Beefy.sol";
@@ -235,6 +236,11 @@ contract DeployScript is BaseScript {
235236
PolkadotHost h = new PolkadotHost{salt: salt}(params);
236237
return address(h);
237238
}
239+
// Pharos (mainnet: 688600, testnet: 688689)
240+
else if (chainId == 688600 || chainId == 688689) {
241+
PharosHost h = new PharosHost{salt: salt}(params);
242+
return address(h);
243+
}
238244

239245
revert("Unknown chain ID");
240246
}

evm/script/deploy.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ print_usage() {
6666
echo ""
6767
echo "Available Chains:"
6868
echo " Testnets: sepolia, optimism-sepolia, arbitrum-sepolia, base-sepolia,"
69-
echo " polygon-amoy, bsc-testnet, gnosis-chiado, sei-testnet"
69+
echo " polygon-amoy, bsc-testnet, gnosis-chiado, sei-testnet, pharos-testnet"
7070
echo ""
7171
echo " Mainnets: ethereum, optimism, arbitrum, base, bsc, gnosis,"
7272
echo " soneium, polygon, unichain, inkchain, sei"
@@ -157,7 +157,7 @@ fi
157157

158158
# Expand "testnet" or "mainnet" to actual chain lists
159159
if [ "$CHAINS" = "testnet" ]; then
160-
CHAINS="sepolia,optimism-sepolia,arbitrum-sepolia,base-sepolia,polygon-amoy,bsc-testnet,polkadot-testnet"
160+
CHAINS="sepolia,optimism-sepolia,arbitrum-sepolia,base-sepolia,polygon-amoy,bsc-testnet,polkadot-testnet,pharos-testnet"
161161
echo -e "${GREEN}Deploying to all testnet chains: ${YELLOW}${CHAINS}${NC}"
162162
echo ""
163163
elif [ "$CHAINS" = "mainnet" ]; then

evm/src/hosts/Pharos.sol

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (C) Polytope Labs Ltd.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
pragma solidity ^0.8.17;
16+
17+
import {EvmHost, HostParams} from "../core/EvmHost.sol";
18+
19+
/**
20+
* @title The PharosHost
21+
* @author Polytope Labs (hello@polytope.technology)
22+
*
23+
* @notice The IsmpHost and IsmpDispatcher implementation for the Pharos state machine.
24+
* Refer to the official ISMP specification. https://docs.hyperbridge.network/protocol/ismp
25+
*/
26+
contract PharosHost is EvmHost {
27+
constructor(HostParams memory params) EvmHost(params) {}
28+
29+
/// chainId for the Pharos mainnet
30+
uint256 public constant CHAIN_ID = 688600;
31+
32+
function chainId() public pure override returns (uint256) {
33+
return CHAIN_ID;
34+
}
35+
}

modules/consensus/pharos/primitives/src/constants.rs

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ pub const PHAROS_CONSENSUS_ID: [u8; 4] = *b"PHAR";
3333
/// Mainnet epoch length in seconds (4 hours)
3434
pub const MAINNET_EPOCH_LENGTH_SECS: u64 = 4 * 60 * 60; // 14400 seconds
3535

36-
/// Testnet (Atlantic) epoch length in seconds.
37-
pub const TESTNET_EPOCH_LENGTH_SECS: u64 = 7828;
36+
/// Testnet (Atlantic) epoch length in seconds (30 minutes).
37+
pub const TESTNET_EPOCH_LENGTH_SECS: u64 = 30 * 60; // 1800 seconds
38+
39+
/// Storage slot index for `currentEpoch` on the Pharos staking precompile.
40+
/// This stores the current epoch **number** (increments every epoch duration).
41+
pub const CURRENT_EPOCH_SLOT: u64 = 5;
3842

3943
/// Pharos Mainnet chain ID
4044
pub const PHAROS_MAINNET_CHAIN_ID: u32 = 688600;
@@ -46,13 +50,18 @@ pub const PHAROS_ATLANTIC_CHAIN_ID: u32 = 688689;
4650
pub const DEFAULT_WITHDRAW_WINDOW_EPOCHS: u64 = 84;
4751

4852
/// Configuration trait for Pharos network parameters.
53+
///
54+
/// Pharos epochs are **time-based** (not block-count-based). The epoch number
55+
/// is stored on-chain at slot 5 of the staking precompile and increments every
56+
/// `EPOCH_LENGTH_SECS` seconds. There is no fixed number of blocks per epoch.
57+
///
58+
/// Epoch determination requires either:
59+
/// - Reading `currentEpoch` from the staking contract (off-chain prover)
60+
/// - Verifying a storage proof of slot 5 against the block's state root (on-chain verifier)
4961
pub trait Config: Clone + Send + Sync {
5062
/// The epoch length in seconds
5163
const EPOCH_LENGTH_SECS: u64;
5264

53-
/// The epoch length in blocks (derived from epoch length and block time)
54-
const EPOCH_LENGTH_BLOCKS: u64;
55-
5665
/// The chain ID for this network
5766
const CHAIN_ID: u64;
5867

@@ -62,27 +71,6 @@ pub trait Config: Clone + Send + Sync {
6271
/// The unstaking period in seconds (withdraw_window_epochs × epoch_length_secs).
6372
/// Defaults to `DEFAULT_WITHDRAW_WINDOW_EPOCHS × EPOCH_LENGTH_SECS`.
6473
const UNBONDING_PERIOD: u64 = DEFAULT_WITHDRAW_WINDOW_EPOCHS * Self::EPOCH_LENGTH_SECS;
65-
66-
/// Calculate the epoch number for a given block number
67-
fn compute_epoch(block_number: u64) -> u64 {
68-
block_number / Self::EPOCH_LENGTH_BLOCKS
69-
}
70-
71-
/// Check if a block is an epoch boundary block (last block of an epoch).
72-
///
73-
/// The epoch boundary is defined as the last block of an epoch, i.e.,
74-
/// `(block_number + 1) % epoch_length == 0`.
75-
///
76-
/// At epoch boundaries, the validator set for the next epoch is finalized
77-
fn is_epoch_boundary(block_number: u64) -> bool {
78-
(block_number + 1) % Self::EPOCH_LENGTH_BLOCKS == 0
79-
}
80-
81-
/// Get the first block number of the next epoch
82-
fn next_epoch_start(current_block: u64) -> u64 {
83-
let current_epoch = Self::compute_epoch(current_block);
84-
(current_epoch + 1) * Self::EPOCH_LENGTH_BLOCKS
85-
}
8674
}
8775

8876
/// Pharos Mainnet configuration
@@ -93,12 +81,6 @@ impl Config for Mainnet {
9381
/// 4 hours epoch length
9482
const EPOCH_LENGTH_SECS: u64 = MAINNET_EPOCH_LENGTH_SECS;
9583

96-
/// With ~1 second finality (sub-second), assuming 1 block per second
97-
/// 4 hours = 14400 blocks
98-
const EPOCH_LENGTH_BLOCKS: u64 = 14400;
99-
100-
/// Mainnet chain ID - TBD
101-
/// Placeholder based on testnet pattern
10284
const CHAIN_ID: u64 = 688600;
10385

10486
const ID: [u8; 4] = PHAROS_CONSENSUS_ID;
@@ -109,11 +91,9 @@ impl Config for Mainnet {
10991
pub struct Testnet;
11092

11193
impl Config for Testnet {
112-
/// ~93.8 minutes epoch length
94+
/// 30 minutes epoch length
11395
const EPOCH_LENGTH_SECS: u64 = TESTNET_EPOCH_LENGTH_SECS;
11496

115-
const EPOCH_LENGTH_BLOCKS: u64 = 7828;
116-
11797
/// Pharos Testnet chain ID
11898
const CHAIN_ID: u64 = 688689;
11999

0 commit comments

Comments
 (0)