Skip to content

Commit

Permalink
add prices info, cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
acharb committed Dec 26, 2023
1 parent 24a3b83 commit 60fdefd
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 27 deletions.
111 changes: 90 additions & 21 deletions src/walletSdk/Anchor/Sep38.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
// ALEC TODO - change file name?
import { AxiosInstance } from "axios";
import queryString from "query-string";

import { Anchor } from "../Anchor";
import { ServerRequestFailedError } from "../Exceptions";
import { AuthToken } from "../Types";

// ALEC TODO - move
interface Sep38DeliveryMethod {
name: string;
description: string;
}
interface Sep38Info {
assets: Array<Sep38AssetInfo>;
}
interface Sep38AssetInfo {
asset: string;
sell_delivery_methods?: Array<Sep38DeliveryMethod>;
buy_delivery_methods?: Array<Sep38DeliveryMethod>;
country_codes?: Array<string>;
}
export type Sep38Params = {
anchor: Anchor;
httpClient: AxiosInstance;
};
import {
AuthToken,
Sep38Info,
Sep38Params,
Sep38PricesParams,
Sep38PriceParams,
Sep38PricesResponse,
Sep38PriceResponse,
} from "../Types";
import { camelToSnakeCaseObject } from "../Utils";

export class Sep38 {
private anchor: Anchor;
Expand Down Expand Up @@ -74,4 +64,83 @@ export class Sep38 {
throw new ServerRequestFailedError(e);
}
}

/**
* Get indicative prices of off-chain assets in exchange for a Stellar asset, or vice versa,
* from an anchor using Sep-38.
* @param {object} options - The options for the request
* @param {Sep38PricesParams} options.params - The parameters for the GET prices request.
* @param {AuthToken} [options.authToken] - The authentication token. This may be optional
* if the anchor does not require it.
* @returns {Promise<Sep38PricesResponse>} - SEP-38 /prices response.
*/
async prices({
params,
authToken,
}: {
params: Sep38PricesParams;
authToken?: AuthToken;
}): Promise<Sep38PricesResponse> {
const { anchorQuoteServer } = await this.anchor.sep1();
let headers;
if (authToken) {
headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${authToken.token}`,
};
}

try {
const resp = await this.httpClient.get(
`${anchorQuoteServer}/prices?${queryString.stringify(
camelToSnakeCaseObject(params),
)}`,
{
headers,
},
);
return resp.data;
} catch (e) {
throw new ServerRequestFailedError(e);
}
}

/**
* Get an indicative price for an an asset pair from and anchor using SEP-38.
* @param {object} options - The options for the request
* @param {Sep38PriceParams} options.params - The parameters for the GET price request.
* @param {AuthToken} [options.authToken] - The authentication token. This may be optional
* if the anchor does not require it.
* @returns {Promise<Sep38PriceResponse>} - SEP-38 /price response.
*/
async price({
params,
authToken,
}: {
params: Sep38PriceParams;
authToken?: AuthToken;
}): Promise<Sep38PriceResponse> {
const { anchorQuoteServer } = await this.anchor.sep1();
let headers;
if (authToken) {
headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${authToken.token}`,
};
}

try {
const resp = await this.httpClient.get(
`${anchorQuoteServer}/price?${queryString.stringify(
camelToSnakeCaseObject(params),
)}`,
{
headers,
},
);
return resp.data;
} catch (e) {
throw new ServerRequestFailedError(e);
}
}
}
20 changes: 15 additions & 5 deletions src/walletSdk/Anchor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ type AnchorParams = {

export type Transfer = Sep6;

export type Interactive = Sep24;

export type Auth = Sep10;

export type Customer = Sep12;

// ALEC TODO - alias for sep38
export type Interactive = Sep24;

export type Quote = Sep38;

/**
* Build on/off ramps with anchors.
Expand Down Expand Up @@ -166,12 +166,22 @@ export class Anchor {
return this.sep24();
}

// ALEC TODO - jsdoc
/**
* Creates a new quote service. It can be used for getting price quotes from an anchor
* for exchanging assets.
* @returns {Sep38} - quote service.
*/
sep38(): Sep38 {
return new Sep38({ anchor: this, httpClient: this.httpClient });
}

// ALEC TODO - sep38 alias method
/**
* Creates a new quote service using the `sep38` method.
* @returns {Quote} - quote service.
*/
quote(): Quote {
return this.sep38();
}

/**
* Get information about an Anchor.
Expand Down
1 change: 1 addition & 0 deletions src/walletSdk/Types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ export * from "./recovery";
export * from "./sep6";
export * from "./sep12";
export * from "./sep24";
export * from "./sep38";
export * from "./utils";
export * from "./watcher";
75 changes: 75 additions & 0 deletions src/walletSdk/Types/sep38.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { AxiosInstance } from "axios";
import { Anchor } from "../Anchor";

export interface Sep38Info {
assets: Array<Sep38AssetInfo>;
}

export interface Sep38AssetInfo {
asset: string;
sell_delivery_methods?: Array<Sep38DeliveryMethod>;
buy_delivery_methods?: Array<Sep38DeliveryMethod>;
country_codes?: Array<string>;
}

export interface Sep38DeliveryMethod {
name: string;
description: string;
}

export type Sep38Params = {
anchor: Anchor;
httpClient: AxiosInstance;
};

export interface Sep38PricesParams {
sellAsset: string;
sellAmount: string;
sellDeliveryMethod?: string;
buyDeliveryMethod?: string;
countryCode?: string;
}

export interface Sep38PricesResponse {
buy_assets: Array<Sep38BuyAsset>;
}

export interface Sep38BuyAsset {
asset: string;
price: string;
decimals: number;
}

export interface Sep38PriceParams {
sellAsset: string;
buyAsset: string;
sellAmount?: string;
buyAmount?: string;
context: Sep38PriceContext;
sellDeliveryMethod?: string;
buyDeliveryMethod?: string;
countryCode?: string;
}

export enum Sep38PriceContext {
SEP6 = "sep6",
SEP31 = "sep31",
}

export interface Sep38PriceResponse {
total_price: string;
price: string;
sell_amount: string;
buy_amount: string;
fee: {
total: string;
asset: string;
details?: Array<Sep38FeeDetails>;
};
}

export interface Sep38FeeDetails {
name: string;
description?: string;
amount: string;
}
29 changes: 28 additions & 1 deletion test/sep38.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// ALEC TODO - file test name
import { Wallet } from "../src";

let wallet;
let anchor;
let sep38;
let accountKp;

describe("SEP-38", () => {
beforeAll(() => {
wallet = Wallet.TestNet();
anchor = wallet.anchor({ homeDomain: "testanchor.stellar.org" });
sep38 = anchor.sep38();
accountKp = accountKp = wallet.stellar().account().createKeypair();
}, 10000);

it("should get Sep-38 anchor info", async () => {
Expand All @@ -19,4 +20,30 @@ describe("SEP-38", () => {
const refreshed = await sep38.info(true);
expect(refreshed.assets[0]).toBeTruthy();
});

it("should get Sep-38 prices", async () => {
const auth = await anchor.sep10();
const authToken = await auth.authenticate({ accountKp });
const params = {
sell_asset: "iso4217:USD",
sell_amount: "5",
sell_delivery_method: "ach_debit",
};
const resp = await sep38.prices({ params, authToken });
expect(resp.buy_assets[0].asset).toBeTruthy();
});

it("should get Sep-38 price", async () => {
const auth = await anchor.sep10();
const authToken = await auth.authenticate({ accountKp });
const params = {
sell_asset: "iso4217:USD",
buy_asset:
"stellar:SRT:GCDNJUBQSX7AJWLJACMJ7I4BC3Z47BQUTMHEICZLE6MU4KQBRYG5JY6B",
sell_amount: "5",
context: "sep6",
};
const resp = await sep38.price({ params, authToken });
expect(resp.price).toBeTruthy();
});
});

0 comments on commit 60fdefd

Please sign in to comment.