filecoin-pin
Version:
Bridge IPFS content to Filecoin Onchain Cloud using familiar tools
136 lines • 6.73 kB
JavaScript
/**
* Automatic payment setup flow
*
* This module provides an automated, non-interactive setup experience for
* configuring payment approvals. It uses default values and command-line
* options to complete the setup without user interaction.
*/
import { ethers } from 'ethers';
import pc from 'picocolors';
import { TELEMETRY_CLI_APP_NAME } from '../common/constants.js';
import { calculateDepositCapacity, checkAndSetAllowances, checkFILBalance, checkUSDFCBalance, depositUSDFC, getPaymentStatus, validatePaymentRequirements, } from '../core/payments/index.js';
import { cleanupSynapseService, initializeSynapse } from '../core/synapse/index.js';
import { formatUSDFC } from '../core/utils/format.js';
import { getCLILogger, parseCLIAuth } from '../utils/cli-auth.js';
import { cancel, createSpinner, intro, outro } from '../utils/cli-helpers.js';
import { log } from '../utils/cli-logger.js';
import { displayAccountInfo, displayDepositWarning } from './setup.js';
/**
* Run automatic payment setup with defaults
*
* @param options - Options from command line
*/
export async function runAutoSetup(options) {
intro(pc.bold('Filecoin Onchain Cloud Payment Setup'));
log.message(pc.gray('Running in auto mode...'));
// Parse and validate deposit amount
let targetFilecoinPayBalance;
try {
targetFilecoinPayBalance = ethers.parseUnits(options.deposit, 18);
}
catch {
console.error(pc.red(`Error: Invalid deposit amount '${options.deposit}'`));
process.exit(1);
}
const spinner = createSpinner();
spinner.start('Initializing connection...');
try {
// Parse and validate authentication
const authConfig = parseCLIAuth(options);
const logger = getCLILogger();
const synapse = await initializeSynapse({ ...authConfig, telemetry: { sentrySetTags: { appName: TELEMETRY_CLI_APP_NAME } } }, logger);
const network = synapse.getNetwork();
const client = synapse.getClient();
const address = await client.getAddress();
spinner.stop(`${pc.green('✓')} Connected to ${pc.bold(network)}`);
// Check balances
spinner.start('Checking balances...');
const filStatus = await checkFILBalance(synapse);
const walletUsdfcBalance = await checkUSDFCBalance(synapse);
spinner.stop(`${pc.green('✓')} Balance check complete`);
// Validate payment requirements
const validation = validatePaymentRequirements(filStatus.hasSufficientGas, walletUsdfcBalance, filStatus.isCalibnet);
if (!validation.isValid) {
log.line(`${pc.red('✗')} ${validation.errorMessage}`);
if (validation.helpMessage) {
log.line('');
log.line(` ${pc.cyan(validation.helpMessage)}`);
}
log.flush();
cancel('Please fund your wallet and try again');
process.exit(1);
}
// Now safe to get payment status since we know account exists
const status = await getPaymentStatus(synapse);
// Display account and balance info using shared function
displayAccountInfo(address, network, filStatus.balance, filStatus.isCalibnet, filStatus.hasSufficientGas, walletUsdfcBalance, status.filecoinPayBalance);
// Get storage pricing for capacity calculation
const storageInfo = await synapse.storage.getStorageInfo();
const pricePerTiBPerEpoch = storageInfo.pricing.noCDN.perTiBPerEpoch;
// Track if any changes were made
let actionsTaken = false;
let actualFilecoinPayTopUp = 0n;
if (status.filecoinPayBalance < targetFilecoinPayBalance) {
const neededFilecoinPayTopUp = targetFilecoinPayBalance - status.filecoinPayBalance;
actualFilecoinPayTopUp = neededFilecoinPayTopUp;
if (neededFilecoinPayTopUp > walletUsdfcBalance) {
console.error(pc.red(`✗ Insufficient USDFC for deposit (need ${formatUSDFC(neededFilecoinPayTopUp)} USDFC, have ${formatUSDFC(walletUsdfcBalance)} USDFC)`));
process.exit(1);
}
spinner.start(`Depositing ${formatUSDFC(neededFilecoinPayTopUp)} USDFC...`);
const { depositTx } = await depositUSDFC(synapse, neededFilecoinPayTopUp);
spinner.stop(`${pc.green('✓')} Deposited ${formatUSDFC(neededFilecoinPayTopUp)} USDFC`);
actionsTaken = true;
log.line(pc.bold('Transaction details:'));
log.indent(pc.gray(`Deposit: ${depositTx}`));
log.flush();
}
else {
// Use a dummy spinner to get consistent formatting
spinner.start('Checking deposit...');
const { updated, transactionHash } = await checkAndSetAllowances(synapse);
if (updated) {
spinner.stop(`${pc.green('✓')} Updated payment allowances, tx: ${transactionHash}`);
}
else {
spinner.stop(`${pc.green('✓')} Deposit already sufficient (${formatUSDFC(status.filecoinPayBalance)} USDFC)`);
}
}
// Calculate capacity for final summary
const totalDeposit = status.filecoinPayBalance + actualFilecoinPayTopUp;
const capacity = calculateDepositCapacity(totalDeposit, pricePerTiBPerEpoch);
// Final summary
spinner.start('Completing setup...');
spinner.stop('━━━ Configuration Summary ━━━');
log.line(`Network: ${pc.bold(network)}`);
log.line(`Deposit: ${formatUSDFC(totalDeposit)} USDFC`);
if (capacity.gibPerMonth > 0) {
const capacityStr = capacity.gibPerMonth >= 1024
? `${(capacity.gibPerMonth / 1024).toFixed(1)} TiB`
: `${capacity.gibPerMonth.toFixed(1)} GiB`;
log.line(`Storage: ~${capacityStr} for 1 month`);
}
log.line(`Status: ${pc.green('Ready to upload')}`);
log.flush();
// Show deposit warning if needed
displayDepositWarning(totalDeposit, status.currentAllowances.lockupUsed);
// Show appropriate outro message based on whether actions were taken
if (actionsTaken) {
outro('Payment setup completed successfully');
}
else {
outro('Payment setup already configured - ready to use');
}
}
catch (error) {
spinner.stop(); // Stop spinner without message
console.error(pc.red('✗ Setup failed'));
console.error(pc.red('Error:'), error instanceof Error ? error.message : error);
process.exitCode = 1;
}
finally {
await cleanupSynapseService();
process.exit();
}
}
//# sourceMappingURL=auto.js.map