The foundation's Union validator onboarding is in progress. Deposits open after the external security audit. All numbers shown are illustrative.
Every epoch, 100% of the foundation node's validator rewards flow in. The staker pool is sized against the full 35M cap: stakers receive 60% × filled capacity, and everything else — the base 40% plus every unfilled seat's share — is sent to the burn address, gone forever. No re-delegation, no lockup of principal beyond a 7-day cooldown.
Anyone can call settle() once per epoch — it's permissionless. Principal and the
reward pool are accounted separately, so even if the node is slashed or rewards stop, every
staker can withdraw 100% of principal.
// ethers v6
const vault = new ethers.Contract(VAULT, ABI, signer);
// direct:
await vault.depositNative(receiver, { value: amount });
// via a partner referral (id = keccak256 of the partner slug):
const pid = ethers.id("ankr");
await vault.depositNativeWithReferral(receiver, pid, { value: amount });
Unstaking is a two-step, 7-day cooldown: requestRedeem burns your shares now,
then claimRedeem returns principal after 7 days.
// step 1 — request (shares = assets × 1000, fixed rate)
const shares = ethers.parseEther(amount) * 1000n;
const id = await vault.requestRedeem(shares, owner, owner);
// step 2 — after 7 days
await vault.claimRedeemNative(requestId, receiver);
// rewards accrue every second while staked
await vault.claimRewardNative(receiver); // native XP
// or keep it wrapped:
await vault.claimReward(receiver); // WXP
External staking platforms route their users into this single vault with an on-chain
partnerId. Attribution is fully transparent — anyone can verify each
platform's routed TVL directly from the contract via partnerTVL(id).
Partnership terms and onboarding are arranged individually with the Foundation and are not published here. If your platform wants to offer XP staking to its users, reach out through the Foundation's business channel.
Contact the Foundation →
Every contract is public and permissionless to read. Reads work with any RPC; writes need a
signer. Addresses live in config.js.
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider(XPHERE_RPC);
const vault = new ethers.Contract(VAULT, [
"function totalAssets() view returns (uint256)",
"function currentAPR() view returns (uint256)",
"function partnerTVL(bytes32) view returns (uint256)",
"function earned(address) view returns (uint256)",
"function depositNative(address) payable returns (uint256)",
"function requestRedeem(uint256,address,address) returns (uint256)",
], provider);
// read effective APR (1e18 == 100%)
const apr = await vault.currentAPR();
console.log(Number(apr) / 1e16, "%");
// stake (with a signer)
const signer = await new ethers.BrowserProvider(window.ethereum).getSigner();
await vault.connect(signer).depositNative(await signer.getAddress(), {
value: ethers.parseEther("100"),
});
import { createPublicClient, http, parseEther, formatUnits } from "viem";
const client = createPublicClient({ transport: http(XPHERE_RPC) });
const apr = await client.readContract({
address: VAULT,
abi: [{ name: "currentAPR", type: "function", stateMutability: "view",
inputs: [], outputs: [{ type: "uint256" }] }],
functionName: "currentAPR",
});
console.log(formatUnits(apr, 16), "%");
// total burned (from the distributor)
const burned = await client.readContract({
address: DISTRIBUTOR,
abi: [{ name: "totalBurned", type: "function", stateMutability: "view",
inputs: [], outputs: [{ type: "uint256" }] }],
functionName: "totalBurned",
});
# Foundry cast — read state
cast call $VAULT "totalAssets()(uint256)" --rpc-url $XPHERE_RPC
cast call $VAULT "currentAPR()(uint256)" --rpc-url $XPHERE_RPC
cast call $DISTRIBUTOR "totalBurned()(uint256)" --rpc-url $XPHERE_RPC
# partner TVL (bytes32 id = keccak of the slug)
PID=$(cast keccak "ankr")
cast call $VAULT "partnerTVL(bytes32)(uint256)" $PID --rpc-url $XPHERE_RPC
# stake 100 XP (native), signed
cast send $VAULT "depositNative(address)(uint256)" $YOU \
--value 100ether --rpc-url $XPHERE_RPC --private-key $PK
# settle the epoch (permissionless)
cast send $DISTRIBUTOR "settle()(uint256,uint256)" --rpc-url $XPHERE_RPC --private-key $PK