Skip to content

Commit

Permalink
feat: add remaining unauthenticated apis for payment service, introdu…
Browse files Browse the repository at this point in the history
…ce some new types, add tests
  • Loading branch information
dtfiedler committed Aug 18, 2023
1 parent c39628f commit 8d56fd7
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 31 deletions.
77 changes: 77 additions & 0 deletions src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import { JWKInterface } from '../types/index.js';
import {
Turbo,
TurboConfiguration,
TurboCountriesResponse,
TurboCurrenciesResponse,
TurboPriceResponse,
TurboRateResponse,
TurboRatesResponse,
} from '../types/turbo.js';
import { createAxiosInstance } from '../utils/axiosClient.js';
Expand Down Expand Up @@ -77,9 +81,82 @@ export abstract class TurboClient implements Turbo {
if (status !== 200) {
throw new Error(`Status: ${status} ${statusText}`);
}

// TODO: should we return just the fiat rates instead of the whole response?
return rates as TurboRatesResponse;
}

async getRate(currency: string): Promise<TurboRateResponse> {
const {
status,
statusText,
data: rate,
} = await this.paymentService.get(`/rates/${currency}`);

if (status !== 200) {
throw new Error(`Status: ${status} ${statusText}`);
}

// TODO: should we return just the fiat rates instead of the whole response?
return rate as TurboRateResponse;
}

async getCountries(): Promise<TurboCountriesResponse> {
const {
status,
statusText,
data: countries,
} = await this.paymentService.get('/countries');

if (status !== 200) {
throw new Error(`Status: ${status} ${statusText}`);
}

return countries as TurboCountriesResponse;
}

async getCurrencies(): Promise<TurboCurrenciesResponse> {
const {
status,
statusText,
data: currencies,
} = await this.paymentService.get('/currencies');

if (status !== 200) {
throw new Error(`Status: ${status} ${statusText}`);
}

return currencies as TurboCurrenciesResponse;
}

async getWincPriceForBytes(bytes: number): Promise<TurboPriceResponse> {
const {
status,
statusText,
data: wincForBytes,
} = await this.paymentService.get(`/price/bytes/${bytes}`);

if (status !== 200) {
throw new Error(`Status: ${status} ${statusText}`);
}

return wincForBytes as TurboPriceResponse;
}

async getWincPriceForFiat({ amount, currency }): Promise<TurboPriceResponse> {
const {
status,
statusText,
data: wincForFiat,
} = await this.paymentService.get(`/price/${currency}/${amount}`);

if (status !== 200) {
throw new Error(`Status: ${status} ${statusText}`);
}

return wincForFiat as TurboPriceResponse;
}

async getBalance(): Promise<number> {
if (!this.jwk) {
throw new UnauthenticatedRequestError();
Expand Down
35 changes: 30 additions & 5 deletions src/types/turbo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,31 @@ export type Base64String = string;
export type PublicArweaveAddress = Base64String;
export type TransactionId = Base64String;
export type UserAddress = string | PublicArweaveAddress;
export type Currency = 'USD' | 'EUR' | 'GBP' | 'CAD' | 'AUD' | 'NZD' | 'JPY';
export type TurboRates = Record<Currency, number>;
export type Currency = 'usd' | 'eur' | 'gbp' | 'cad' | 'aud' | 'nzd' | 'jpy';
export type Country = 'United States' | 'United Kingdom' | 'Canada';

export type TurboRatesResponse = {
winc: number;
fiat: TurboRates;
export type CurrencyLimit = {
minimumPaymentAmount: number;
maximumPaymentAmount: number;
suggestedPaymentAmount: number[];
zeroDecimalCurrency: boolean;
};

export type TurboPriceResponse = {
winc: string;
adjustments: any; // TODO: type this
};
export type TurboRateResponse = {
currency: Currency;
rate: number;
};
export type TurboRatesResponse = TurboPriceResponse &
Record<'fiat', Record<Currency, number>>;
export type TurboCountriesResponse = Country[];
export type TurboCurrenciesResponse = {
supportedCurrencies: Currency[];
limits: Record<Currency, CurrencyLimit>;
};

export type TurboRequestHeaders = {
'x-public-key': string;
Expand All @@ -52,7 +69,15 @@ export interface AuthenticatedTurboPaymentService {
}

export interface UnauthenticatedTurboPaymentService {
getCurrencies(): Promise<TurboCurrenciesResponse>;
getCountries(): Promise<TurboCountriesResponse>;
getRate(currency: Currency): Promise<TurboRateResponse>;
getRates(): Promise<TurboRatesResponse>;
getWincPriceForFiat({
amount,
currency,
}): Promise<Omit<TurboPriceResponse, 'adjustments'>>;
getWincPriceForBytes(bytes: number): Promise<TurboPriceResponse>;
}

export interface TurboPaymentService
Expand Down
88 changes: 62 additions & 26 deletions tests/turbo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,65 @@ describe('TurboFactory', () => {
});
});

describe('TurboNodeClient', () => {
describe('unauthenticated requests', () => {
let turbo: TurboClient;
describe('TurboClient', () => {
let turbo: TurboClient;

before(async () => {
turbo = TurboFactory.init();
});
before(async () => {
turbo = TurboFactory.init();
});

describe('unauthenticated requests', () => {
it('getRates()', async () => {
const { winc, fiat, adjustments } = await turbo.getRates();
expect(winc).to.not.be.undefined.and.to.be.a('number');
expect(fiat).to.have.property('usd').that.is.a('number');
expect(adjustments).to.not.be.undefined;
});

it('getRate()', async () => {
const { currency, rate } = await turbo.getRate('usd');
expect(currency).to.equal('usd');
expect(rate).to.be.a('number');
});

it('getCountries()', async () => {
const countries = await turbo.getCountries();
expect(countries).to.be.an('array');
expect(countries.length).to.be.greaterThan(0);
expect(countries).to.include('United States');
});

it('getCurrencies()', async () => {
const { supportedCurrencies, limits } = await turbo.getCurrencies();
expect(supportedCurrencies).to.not.be.undefined;
expect(supportedCurrencies).to.be.an('array');
expect(supportedCurrencies.length).to.be.greaterThan(0);
expect(supportedCurrencies).to.include('usd');
expect(limits).to.not.be.undefined;
expect(limits).to.be.an('object');
expect(limits).to.have.property('usd');
expect(limits.usd).to.have.property('minimumPaymentAmount');
expect(limits.usd).to.have.property('maximumPaymentAmount');
expect(limits.usd).to.have.property('suggestedPaymentAmounts');
expect(limits.usd).to.have.property('zeroDecimalCurrency');
});

it('getWincPriceForBytes()', async () => {
const { winc, adjustments } = await turbo.getWincPriceForBytes(1024);
expect(winc).to.not.be.undefined;
expect(+winc).to.be.greaterThan(0);
expect(adjustments).to.not.be.undefined;
expect(adjustments).to.be.an('array');
});

it('getPriceForFiat()', async () => {
const { winc } = await turbo.getWincPriceForFiat({
amount: 1000, // 10 USD
currency: 'usd',
});
expect(winc).to.not.be.undefined;
expect(+winc).to.be.greaterThan(0);
});
});

describe('authenticated requests', () => {
Expand All @@ -49,35 +95,25 @@ describe('TurboNodeClient', () => {
expect(balance).to.equal(0);
});
});
});

describe('TurboWebClient', () => {
describe('unauthenticated requests', () => {
let turbo: TurboClient;

describe('TurboNodeClient', () => {
before(async () => {
turbo = TurboFactory.init();
});
it('getRates()', async () => {
const { winc, fiat, adjustments } = await turbo.getRates();
expect(winc).to.not.be.undefined.and.to.be.a('number');
expect(fiat).to.have.property('usd').that.is.a('number');
expect(adjustments).to.not.be.undefined;
});
});

describe('authenticated requests', () => {
let jwk: JWKInterface;
let turbo: TurboClient;
// node client specific tests
});

describe('TurboWebClient', () => {
before(async () => {
jwk = await Arweave.crypto.generateJWK();
turbo = TurboFactory.init({ jwk });
(global as any).window = { document: {} };
turbo = TurboFactory.init();
});

it('getBalance()', async () => {
const balance = await turbo.getBalance();
expect(balance).to.equal(0);
after(() => {
delete (global as any).window;
});

// web client specific tests
});
});

0 comments on commit 8d56fd7

Please sign in to comment.