filecoin-pin
Version:
Bridge IPFS content to Filecoin Onchain Cloud using familiar tools
117 lines • 6.23 kB
JavaScript
import { SIZE_CONSTANTS, TIME_CONSTANTS } from '@filoz/synapse-sdk';
import { describe, expect, it } from 'vitest';
import { applyFloorPricing, BUFFER_DENOMINATOR, BUFFER_NUMERATOR, calculatePieceUploadRequirements, calculateRequiredAllowances, computeAdjustmentForExactDaysWithPiece, DEFAULT_LOCKUP_DAYS, getFloorAllowances, } from '../../core/payments/index.js';
function makeStatus(params) {
const currentAllowances = {
rateAllowance: 0n,
lockupAllowance: 0n,
lockupUsed: params.lockupUsed ?? 0n,
rateUsed: params.rateUsed ?? 0n,
maxLockupPeriod: BigInt(DEFAULT_LOCKUP_DAYS) * TIME_CONSTANTS.EPOCHS_PER_DAY,
};
return {
network: 'calibration',
address: '0x0000000000000000000000000000000000000000',
filBalance: 0n,
walletUsdfcBalance: 0n,
filecoinPayBalance: params.filecoinPayBalance,
currentAllowances,
};
}
function getBufferedFloorDeposit() {
const floor = getFloorAllowances();
return (floor.lockupAllowance * BUFFER_NUMERATOR) / BUFFER_DENOMINATOR;
}
describe('applyFloorPricing', () => {
const mockPricing = 100000000000000n; // Some arbitrary price per TiB per epoch
const smallCases = [
{ label: 'tiny file (1 byte)', size: 1 },
{ label: 'small file (1 KB)', size: 1024 },
{ label: 'medium file (1 MB)', size: 1024 * 1024 },
];
for (const { label, size } of smallCases) {
it(`applies floor pricing to ${label}`, () => {
const baseAllowances = calculateRequiredAllowances(size, mockPricing);
const floorAdjusted = applyFloorPricing(baseAllowances);
const floor = getFloorAllowances();
expect(floorAdjusted.rateAllowance).toBe(floor.rateAllowance);
expect(floorAdjusted.lockupAllowance).toBe(floor.lockupAllowance);
});
}
it('does not apply floor for large file when base cost exceeds floor', () => {
// Use a very high price to ensure base cost exceeds floor
const highPrice = 1000000000000000000n; // 1 USDFC per TiB per epoch
const largeFile = Number(SIZE_CONSTANTS.GiB) * 100; // 100 GiB
const baseAllowances = calculateRequiredAllowances(largeFile, highPrice);
const floorAdjusted = applyFloorPricing(baseAllowances);
const floor = getFloorAllowances();
// Base cost should exceed floor, so base is returned
expect(floorAdjusted.rateAllowance).toBeGreaterThan(floor.rateAllowance);
expect(floorAdjusted.lockupAllowance).toBeGreaterThan(floor.lockupAllowance);
expect(floorAdjusted.rateAllowance).toBe(baseAllowances.rateAllowance);
});
});
describe('calculatePieceUploadRequirements - Floor Pricing Integration', () => {
const mockPricing = 100000000000000n;
const floorSizes = [
{ label: '0-byte file', size: 0 },
{ label: '1 KB file', size: 1024 },
];
for (const { label, size } of floorSizes) {
it(`enforces floor price for ${label}`, () => {
const status = makeStatus({ filecoinPayBalance: 0n });
const requirements = calculatePieceUploadRequirements(status, size, mockPricing);
const floor = getFloorAllowances();
expect(requirements.required.rateAllowance).toBe(floor.rateAllowance);
expect(requirements.required.lockupAllowance).toBe(floor.lockupAllowance);
});
}
it('requires deposit with 10% buffer applied', () => {
const status = makeStatus({ filecoinPayBalance: 0n });
const requirements = calculatePieceUploadRequirements(status, 0, mockPricing);
const bufferedFloor = getBufferedFloorDeposit();
expect(requirements.totalDepositNeeded).toBe(bufferedFloor);
// User needs to deposit the buffered amount
expect(requirements.insufficientDeposit).toBe(bufferedFloor);
expect(requirements.canUpload).toBe(false);
});
it('allows upload when deposit meets buffered floor price', () => {
const bufferedFloor = getBufferedFloorDeposit();
const status = makeStatus({ filecoinPayBalance: bufferedFloor });
const requirements = calculatePieceUploadRequirements(status, 0, mockPricing);
expect(requirements.canUpload).toBe(true);
expect(requirements.insufficientDeposit).toBe(0n);
});
it('blocks upload when deposit is below buffered floor price', () => {
const bufferedFloor = getBufferedFloorDeposit();
const slightlyLess = bufferedFloor - 1n;
const status = makeStatus({ filecoinPayBalance: slightlyLess });
const requirements = calculatePieceUploadRequirements(status, 0, mockPricing);
expect(requirements.canUpload).toBe(false);
expect(requirements.insufficientDeposit).toBe(1n);
});
});
describe('computeAdjustmentForExactDaysWithPiece - Floor Pricing Integration', () => {
const mockPricing = 100000000000000n;
it('applies floor pricing for small file in auto-fund calculation', () => {
const status = makeStatus({ filecoinPayBalance: 0n, lockupUsed: 0n, rateUsed: 0n });
const adjustment = computeAdjustmentForExactDaysWithPiece(status, 30, 1024, mockPricing);
const floor = getFloorAllowances();
// Should use floor-adjusted allowances
expect(adjustment.newRateUsed).toBe(floor.rateAllowance);
expect(adjustment.newLockupUsed).toBe(floor.lockupAllowance);
});
it('calculates correct deposit delta with floor pricing', () => {
const status = makeStatus({ filecoinPayBalance: 0n, lockupUsed: 0n, rateUsed: 0n });
const adjustment = computeAdjustmentForExactDaysWithPiece(status, 30, 0, mockPricing);
const floor = getFloorAllowances();
// Target deposit = buffered lockup + runway
const bufferedLockup = getBufferedFloorDeposit();
const perDay = floor.rateAllowance * TIME_CONSTANTS.EPOCHS_PER_DAY;
const safety = perDay > 0n ? perDay / 24n : 1n;
const runwayCost = 30n * perDay + safety;
expect(adjustment.delta).toBeGreaterThan(0n);
expect(adjustment.targetDeposit).toBe(bufferedLockup + runwayCost);
});
});
//# sourceMappingURL=floor-pricing.test.js.map