diff --git a/src/common/payment.ts b/src/common/payment.ts index afd053e7..c3375285 100644 --- a/src/common/payment.ts +++ b/src/common/payment.ts @@ -51,6 +51,7 @@ import { } from '../types.js'; import { TurboHTTPService } from './http.js'; import { TurboWinstonLogger } from './logger.js'; +import { exponentMap, tokenToBaseMap } from './token/index.js'; export const developmentPaymentServiceURL = 'https://payment.ardrive.dev'; export const defaultPaymentServiceURL = 'https://payment.ardrive.io'; @@ -287,6 +288,33 @@ export class TurboUnauthenticatedPaymentService } return response; } + + public async getTokenPriceForBytes({ + bytes, + }: { + bytes: number; + }): Promise<{ tokenPrice: string; bytes: number; token: TokenType }> { + const wincPriceForOneToken = ( + await this.getWincForToken({ + tokenAmount: tokenToBaseMap[this.token](1), + }) + ).winc; + const wincPriceForOneGiB = ( + await this.getUploadCosts({ + bytes: [2 ** 30], + }) + )[0].winc; + + const tokenPriceForOneGiB = new BigNumber(wincPriceForOneGiB).dividedBy( + wincPriceForOneToken, + ); + const tokenPriceForBytes = tokenPriceForOneGiB + .dividedBy(2 ** 30) + .times(bytes) + .toFixed(exponentMap[this.token]); + + return { bytes, tokenPrice: tokenPriceForBytes, token: this.token }; + } } // NOTE: to avoid redundancy, we use inheritance here - but generally prefer composition over inheritance export class TurboAuthenticatedPaymentService diff --git a/src/common/token/index.ts b/src/common/token/index.ts index f244e73b..c49fe1c7 100644 --- a/src/common/token/index.ts +++ b/src/common/token/index.ts @@ -36,6 +36,15 @@ export const defaultTokenMap: TokenFactory = { pol: (config: TokenConfig) => new PolygonToken(config), } as const; +export const exponentMap: Record = { + arweave: 12, + solana: 9, + ethereum: 18, + kyve: 6, + matic: 18, + pol: 18, +} as const; + export const tokenToBaseMap: Record< TokenType, (a: BigNumber.Value) => BigNumber.Value diff --git a/src/common/turbo.ts b/src/common/turbo.ts index 7b79e75a..4c4e03dd 100644 --- a/src/common/turbo.ts +++ b/src/common/turbo.ts @@ -40,6 +40,7 @@ import { TurboRevokeCreditsParams, TurboSignedDataItemFactory, TurboSubmitFundTxResponse, + TurboTokenPriceForBytesResponse, TurboUnauthenticatedClientConfiguration, TurboUnauthenticatedClientInterface, TurboUnauthenticatedPaymentServiceInterface, @@ -169,6 +170,17 @@ export class TurboUnauthenticatedClient return this.paymentService.getWincForToken(params); } + /** + * Determines the price in the instantiated token to upload one data item of a specific size in bytes, including all Turbo cost adjustments and fees. + */ + getTokenPriceForBytes({ + bytes, + }: { + bytes: number; + }): Promise { + return this.paymentService.getTokenPriceForBytes({ bytes }); + } + /** * Uploads a signed data item to the Turbo Upload Service. */ diff --git a/src/types.ts b/src/types.ts index 5ee78bbb..aba975d5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -109,6 +109,12 @@ export type TurboWincForTokenResponse = Omit< equivalentWincTokenAmount: string; }; +export type TurboTokenPriceForBytesResponse = { + tokenPrice: string; + bytes: number; + token: TokenType; +}; + export type TurboWincForFiatParams = { amount: CurrencyMap; nativeAddress?: NativeAddress; @@ -580,6 +586,11 @@ export interface TurboUnauthenticatedPaymentServiceInterface { getWincForToken( params: TurboWincForTokenParams, ): Promise; + getTokenPriceForBytes({ + bytes, + }: { + bytes: number; + }): Promise; getUploadCosts({ bytes }: { bytes: number[] }): Promise; createCheckoutSession( params: TurboCheckoutSessionParams,