feat/ponder-lm-indexing (#142)
This commit is contained in:
parent
de3c8eef94
commit
31063379a8
107 changed files with 12517 additions and 367 deletions
198
tests/e2e/usertest/setup-chain-state.ts
Normal file
198
tests/e2e/usertest/setup-chain-state.ts
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/**
|
||||
* Chain State Setup Script
|
||||
*
|
||||
* Prepares a realistic staking environment BEFORE tests run:
|
||||
* 1. Funds test wallets (Anvil #3, #4, #5) with ETH + KRK
|
||||
* 2. Creates active positions at different tax rates
|
||||
* 3. Triggers a recenter to update pool state
|
||||
* 4. Advances time to simulate position age
|
||||
* 5. Takes chain snapshot for test resets
|
||||
*/
|
||||
|
||||
import { ethers } from 'ethers';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
const RPC_URL = process.env.STACK_RPC_URL ?? 'http://localhost:8545';
|
||||
|
||||
// Anvil test accounts (private keys)
|
||||
const DEPLOYER_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; // Anvil #0
|
||||
const MARCUS_KEY = '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6'; // Anvil #3
|
||||
const SARAH_KEY = '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a'; // Anvil #4
|
||||
const PRIYA_KEY = '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba'; // Anvil #5
|
||||
|
||||
interface ContractAddresses {
|
||||
Kraiken: string;
|
||||
Stake: string;
|
||||
LiquidityManager: string;
|
||||
}
|
||||
|
||||
async function loadContracts(): Promise<ContractAddresses> {
|
||||
const deploymentsPath = join(process.cwd(), 'onchain', 'deployments-local.json');
|
||||
const deploymentsJson = readFileSync(deploymentsPath, 'utf-8');
|
||||
const deployments = JSON.parse(deploymentsJson);
|
||||
return deployments.contracts;
|
||||
}
|
||||
|
||||
async function sendRpc(method: string, params: unknown[]): Promise<any> {
|
||||
const resp = await fetch(RPC_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params }),
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.error) throw new Error(`RPC ${method} failed: ${data.error.message}`);
|
||||
return data.result;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('[SETUP] Starting chain state preparation...\n');
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
||||
const deployer = new ethers.Wallet(DEPLOYER_KEY, provider);
|
||||
const marcus = new ethers.Wallet(MARCUS_KEY, provider);
|
||||
const sarah = new ethers.Wallet(SARAH_KEY, provider);
|
||||
const priya = new ethers.Wallet(PRIYA_KEY, provider);
|
||||
|
||||
const addresses = await loadContracts();
|
||||
console.log('[SETUP] Contract addresses loaded:');
|
||||
console.log(` - Kraiken: ${addresses.Kraiken}`);
|
||||
console.log(` - Stake: ${addresses.Stake}`);
|
||||
console.log(` - LiquidityManager: ${addresses.LiquidityManager}\n`);
|
||||
|
||||
// Contract ABIs (minimal required functions)
|
||||
const krkAbi = [
|
||||
'function transfer(address to, uint256 amount) returns (bool)',
|
||||
'function balanceOf(address account) view returns (uint256)',
|
||||
'function approve(address spender, uint256 amount) returns (bool)',
|
||||
'function minStake() view returns (uint256)',
|
||||
];
|
||||
|
||||
const stakeAbi = [
|
||||
'function snatch(uint256 assets, address receiver, uint32 taxRate, uint256[] calldata positionsToSnatch) returns (uint256)',
|
||||
'function getPosition(uint256 positionId) view returns (tuple(uint256 share, address owner, uint32 creationTime, uint32 lastTaxTime, uint32 taxRate))',
|
||||
// minStake() is on Kraiken, not Stake
|
||||
'function nextPositionId() view returns (uint256)',
|
||||
];
|
||||
|
||||
const lmAbi = [
|
||||
'function recenter() external returns (bool)',
|
||||
];
|
||||
|
||||
const krk = new ethers.Contract(addresses.Kraiken, krkAbi, deployer);
|
||||
const stake = new ethers.Contract(addresses.Stake, stakeAbi, deployer);
|
||||
const lm = new ethers.Contract(addresses.LiquidityManager, lmAbi, deployer);
|
||||
|
||||
// Step 1: Fund test wallets with ETH
|
||||
console.log('[STEP 1] Funding test wallets with ETH...');
|
||||
const ethAmount = ethers.parseEther('100'); // 100 ETH each
|
||||
|
||||
for (const [name, wallet] of [
|
||||
['Marcus', marcus],
|
||||
['Sarah', sarah],
|
||||
['Priya', priya],
|
||||
]) {
|
||||
await sendRpc('anvil_setBalance', [wallet.address, '0x' + ethAmount.toString(16)]);
|
||||
console.log(` ✓ ${name} (${wallet.address}): 100 ETH`);
|
||||
}
|
||||
|
||||
// Step 2: Transfer KRK from deployer to test wallets
|
||||
console.log('\n[STEP 2] Distributing KRK tokens...');
|
||||
const krkAmount = ethers.parseEther('1000'); // 1000 KRK each
|
||||
|
||||
for (const [name, wallet] of [
|
||||
['Marcus', marcus],
|
||||
['Sarah', sarah],
|
||||
['Priya', priya],
|
||||
]) {
|
||||
const tx = await krk.transfer(wallet.address, krkAmount);
|
||||
await tx.wait();
|
||||
const balance = await krk.balanceOf(wallet.address);
|
||||
console.log(` ✓ ${name}: ${ethers.formatEther(balance)} KRK`);
|
||||
}
|
||||
|
||||
// Step 3: Create staking positions
|
||||
console.log('\n[STEP 3] Creating active staking positions...');
|
||||
|
||||
const minStake = await krk.minStake();
|
||||
console.log(` Minimum stake: ${ethers.formatEther(minStake)} KRK`);
|
||||
|
||||
// Marcus stakes at LOW tax rate (index 2 = 5% yearly)
|
||||
console.log('\n Creating Marcus position (LOW tax)...');
|
||||
const marcusAmount = ethers.parseEther('300');
|
||||
const marcusTaxRate = 2; // 5% yearly (0.0137% daily)
|
||||
|
||||
const marcusKrk = krk.connect(marcus) as typeof krk;
|
||||
const marcusStake = stake.connect(marcus) as typeof stake;
|
||||
|
||||
let approveTx = await marcusKrk.approve(addresses.Stake, marcusAmount);
|
||||
await approveTx.wait();
|
||||
|
||||
// Explicit nonce to avoid stale nonce cache
|
||||
let nonce = await provider.getTransactionCount(marcus.address);
|
||||
let snatchTx = await marcusStake.snatch(marcusAmount, marcus.address, marcusTaxRate, [], { nonce });
|
||||
let receipt = await snatchTx.wait();
|
||||
console.log(` ✓ Marcus position created (300 KRK @ 5% tax)`);
|
||||
|
||||
// Sarah stakes at MEDIUM tax rate (index 10 = 60% yearly)
|
||||
console.log('\n Creating Sarah position (MEDIUM tax)...');
|
||||
const sarahAmount = ethers.parseEther('500');
|
||||
const sarahTaxRate = 10; // 60% yearly (0.1644% daily)
|
||||
|
||||
const sarahKrk = krk.connect(sarah) as typeof krk;
|
||||
const sarahStake = stake.connect(sarah) as typeof stake;
|
||||
|
||||
approveTx = await sarahKrk.approve(addresses.Stake, sarahAmount);
|
||||
await approveTx.wait();
|
||||
|
||||
nonce = await provider.getTransactionCount(sarah.address);
|
||||
snatchTx = await sarahStake.snatch(sarahAmount, sarah.address, sarahTaxRate, [], { nonce });
|
||||
receipt = await snatchTx.wait();
|
||||
console.log(` ✓ Sarah position created (500 KRK @ 60% tax)`);
|
||||
|
||||
// Step 4: Trigger recenter via deployer
|
||||
console.log('\n[STEP 4] Triggering recenter to update liquidity positions...');
|
||||
try {
|
||||
const recenterTx = await lm.recenter();
|
||||
await recenterTx.wait();
|
||||
console.log(' ✓ Recenter successful');
|
||||
} catch (error: any) {
|
||||
console.log(` ⚠ Recenter failed (may be expected): ${error.message}`);
|
||||
}
|
||||
|
||||
// Step 5: Advance time by 1 day
|
||||
console.log('\n[STEP 5] Advancing chain time by 1 day...');
|
||||
const oneDay = 86400; // seconds
|
||||
await sendRpc('anvil_increaseTime', [oneDay]);
|
||||
await sendRpc('anvil_mine', [1]);
|
||||
console.log(' ✓ Time advanced by 1 day');
|
||||
|
||||
// Step 6: Take chain snapshot
|
||||
console.log('\n[STEP 6] Taking chain snapshot for test resets...');
|
||||
const snapshotId = await sendRpc('evm_snapshot', []);
|
||||
console.log(` ✓ Snapshot ID: ${snapshotId}`);
|
||||
|
||||
// Verify final state
|
||||
console.log('\n[VERIFICATION] Final chain state:');
|
||||
const nextPosId = await stake.nextPositionId();
|
||||
console.log(` - Next position ID: ${nextPosId}`);
|
||||
|
||||
for (const [name, wallet] of [
|
||||
['Marcus', marcus],
|
||||
['Sarah', sarah],
|
||||
['Priya', priya],
|
||||
]) {
|
||||
const balance = await krk.balanceOf(wallet.address);
|
||||
console.log(` - ${name} KRK balance: ${ethers.formatEther(balance)} KRK`);
|
||||
}
|
||||
|
||||
console.log('\n✅ Chain state setup complete!');
|
||||
console.log(' Tests can now run against this prepared state.\n');
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error('\n❌ Setup failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue