UNPKG

@wuwei-labs/srsly

Version:
145 lines 7.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const vitest_1 = require("vitest"); vitest_1.vi.mock('../accounts/contract', () => ({ fetchContract: vitest_1.vi.fn(), })); vitest_1.vi.mock('../accounts/config', () => ({ fetchConfig: vitest_1.vi.fn(), })); vitest_1.vi.mock('../utils/rpc', () => ({ createRpc: vitest_1.vi.fn(() => ({ getMinimumBalanceForRentExemption: (size) => ({ // Solana rent formula constants: ACCOUNT_STORAGE_OVERHEAD=128, // lamports_per_byte_year=3_480, exemption_threshold=2 years. send: async () => { const bytes = Number(size) + 128; return BigInt(bytes * 3_480 * 2); }, }), })), })); vitest_1.vi.mock('../utils/config', () => ({ getRpcUrl: () => 'http://localhost:8899', })); const contract_1 = require("../accounts/contract"); const config_1 = require("../accounts/config"); const estimate_1 = require("./estimate"); const constants_1 = require("./constants"); const sizes_1 = require("./sizes"); const constants_2 = require("./constants"); // Rent formula used by our mock — matches Solana mainnet rent-exemption math. const rentFor = (size) => BigInt((size + 128) * 3_480 * 2); (0, vitest_1.describe)('estimateOwnerSetupCost', () => { (0, vitest_1.it)('baseline matches COSTS.md breakdown', async () => { const quote = await (0, estimate_1.estimateOwnerSetupCost)(); const contractStateRent = rentFor(sizes_1.CONTRACT_STATE_SIZE); const rentalStateRent = rentFor(sizes_1.RENTAL_STATE_SIZE); const ataRent = rentFor(constants_2.SPL_ATA_SIZE); (0, vitest_1.expect)(quote.breakdown.contractState).toBe(contractStateRent); (0, vitest_1.expect)(quote.breakdown.rentalStateActive).toBe(rentalStateRent); (0, vitest_1.expect)(quote.breakdown.rentalStateQueued).toBe(rentalStateRent); (0, vitest_1.expect)(quote.breakdown.contractAta).toBe(ataRent); (0, vitest_1.expect)(quote.breakdown.ownerAta).toBe(ataRent); (0, vitest_1.expect)(quote.breakdown.threadInfraBase).toBe(constants_1.MINIMUM_THREAD_FUNDING); (0, vitest_1.expect)(quote.breakdown.executionBudget).toBe(constants_1.DEFAULT_EXECUTION_BUDGET); (0, vitest_1.expect)(quote.rentLamports).toBe(contractStateRent + rentalStateRent * 2n + ataRent + ataRent); (0, vitest_1.expect)(quote.threadLamports).toBe(constants_1.MINIMUM_THREAD_FUNDING + constants_1.DEFAULT_EXECUTION_BUDGET); (0, vitest_1.expect)(quote.txFees).toBe(constants_1.TX_BASE_FEE_LAMPORTS * 2n); (0, vitest_1.expect)(quote.total).toBe(quote.rentLamports + quote.threadLamports + quote.txFees); }); (0, vitest_1.it)('ownerAtaExists skips owner ATA rent', async () => { const with_ = await (0, estimate_1.estimateOwnerSetupCost)(); const without = await (0, estimate_1.estimateOwnerSetupCost)({ ownerAtaExists: true }); const ataRent = rentFor(constants_2.SPL_ATA_SIZE); (0, vitest_1.expect)(with_.total - without.total).toBe(ataRent); (0, vitest_1.expect)(without.breakdown.ownerAta).toBe(0n); }); (0, vitest_1.it)('custom executionBudget flows through to thread funding', async () => { const quote = await (0, estimate_1.estimateOwnerSetupCost)({ executionBudget: { sol: 0.01 } }); (0, vitest_1.expect)(quote.breakdown.executionBudget).toBe(10000000n); (0, vitest_1.expect)(quote.threadLamports).toBe(constants_1.MINIMUM_THREAD_FUNDING + 10000000n); }); }); (0, vitest_1.describe)('estimateBorrowerSetupCost', () => { (0, vitest_1.it)('sums BorrowerState + managed ATA rent + tx fee', async () => { const quote = await (0, estimate_1.estimateBorrowerSetupCost)(); const borrowerStateRent = rentFor(sizes_1.BORROWER_STATE_SIZE); const ataRent = rentFor(constants_2.SPL_ATA_SIZE); (0, vitest_1.expect)(quote.breakdown.borrowerState).toBe(borrowerStateRent); (0, vitest_1.expect)(quote.breakdown.managedAta).toBe(ataRent); (0, vitest_1.expect)(quote.rentLamports).toBe(borrowerStateRent + ataRent); (0, vitest_1.expect)(quote.txFees).toBe(constants_1.TX_BASE_FEE_LAMPORTS); (0, vitest_1.expect)(quote.total).toBe(borrowerStateRent + ataRent + constants_1.TX_BASE_FEE_LAMPORTS); }); }); (0, vitest_1.describe)('estimateRentalCost', () => { const mockContract = (rate) => ({ data: { rate }, address: 'Contract11111111111111111111111111111111111', }); const mockConfig = (overrides = {}) => ({ data: { stardustToAtlas: 100000000n, serviceFeeBps: 1000n, baseBps: 10_000, ...overrides, }, address: 'Config1111111111111111111111111111111111111', }); (0, vitest_1.it)('1 ATLAS/day × 86400s yields 100M Stardust escrow, 10M service fee', async () => { vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue(mockContract(1n)); vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue(mockConfig()); const quote = await (0, estimate_1.estimateRentalCost)({ contract: 'AnyContract', durationSeconds: 86400n, }); (0, vitest_1.expect)(quote.atlasEscrow).toBe(100000000n); (0, vitest_1.expect)(quote.atlasServiceFee).toBe(10000000n); (0, vitest_1.expect)(quote.atlasBid).toBe(0n); (0, vitest_1.expect)(quote.atlasTotal).toBe(100000000n); (0, vitest_1.expect)(quote.serviceFeeBps).toBe(1_000); (0, vitest_1.expect)(quote.solTxFees).toBe(constants_1.TX_BASE_FEE_LAMPORTS); }); (0, vitest_1.it)('rate in Stardust units (rate >= stardustToAtlas) is not rescaled', async () => { // 5 ATLAS/day already in Stardust = 500M. vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue(mockContract(500000000n)); vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue(mockConfig()); const quote = await (0, estimate_1.estimateRentalCost)({ contract: 'AnyContract', durationSeconds: 86400n * 3n, // 3 days }); (0, vitest_1.expect)(quote.atlasEscrow).toBe(1500000000n); }); (0, vitest_1.it)('pro-rates sub-day durations via integer division', async () => { vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue(mockContract(1n)); vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue(mockConfig()); // Half a day -> 50M Stardust. const quote = await (0, estimate_1.estimateRentalCost)({ contract: 'AnyContract', durationSeconds: 43200n, }); (0, vitest_1.expect)(quote.atlasEscrow).toBe(50000000n); (0, vitest_1.expect)(quote.atlasServiceFee).toBe(5000000n); }); (0, vitest_1.it)('bidStardust flows into atlasTotal but not into atlasEscrow', async () => { vitest_1.vi.mocked(contract_1.fetchContract).mockResolvedValue(mockContract(1n)); vitest_1.vi.mocked(config_1.fetchConfig).mockResolvedValue(mockConfig()); const quote = await (0, estimate_1.estimateRentalCost)({ contract: 'AnyContract', durationSeconds: 86400n, bidStardust: 25000000n, }); (0, vitest_1.expect)(quote.atlasEscrow).toBe(100000000n); (0, vitest_1.expect)(quote.atlasBid).toBe(25000000n); (0, vitest_1.expect)(quote.atlasTotal).toBe(125000000n); }); }); (0, vitest_1.describe)('tickBudget', () => { (0, vitest_1.it)('scales by PER_TICK_LAMPORTS', () => { (0, vitest_1.expect)((0, estimate_1.tickBudget)(365)).toBe(365n * constants_1.PER_TICK_LAMPORTS); (0, vitest_1.expect)((0, estimate_1.tickBudget)(0)).toBe(0n); (0, vitest_1.expect)((0, estimate_1.tickBudget)(1000000n)).toBe(1000000n * constants_1.PER_TICK_LAMPORTS); }); }); //# sourceMappingURL=estimate.test.js.map