mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-14 06:02:36 +03:00
450 lines
13 KiB
Markdown
450 lines
13 KiB
Markdown
# Orion Protocol SDK
|
|
|
|
[](https://www.npmjs.com/package/@orionprotocol/sdk)
|
|
[](https://www.npmjs.com/package/@orionprotocol/sdk)
|
|
|
|
# Install
|
|
|
|
```console
|
|
npm i @orionprotocol/sdk
|
|
```
|
|
|
|
# Usage
|
|
|
|
## High level methods
|
|
|
|
### Initialization
|
|
|
|
> :warning: **Ethers ^5.6.0 required**
|
|
|
|
```js
|
|
// Node.js
|
|
import { OrionUnit } from "@orionprotocol/sdk";
|
|
import { Wallet } from "ethers";
|
|
|
|
const orionUnit = new OrionUnit("bsc", "production"); // eth, bsc, ftm available
|
|
const wallet = new Wallet("0x...", orionUnit.provider);
|
|
// OrionUnit is chain-in-environment abstraction
|
|
```
|
|
|
|
```ts
|
|
// Metamask
|
|
import { OrionUnit } from "@orionprotocol/sdk";
|
|
import detectEthereumProvider from "@metamask/detect-provider";
|
|
import { BaseProvider } from "@metamask/providers";
|
|
import { providers } from "ethers";
|
|
|
|
const startApp = async (provider: BaseProvider) => {
|
|
const web3Provider = new providers.Web3Provider(provider);
|
|
await web3Provider.ready;
|
|
const signer = web3Provider.getSigner(); // ready to go
|
|
const orionUnit = new OrionUnit("eth", "production"); // ready to go
|
|
};
|
|
|
|
detectEthereumProvider().then((provider) => {
|
|
if (provider) {
|
|
startApp(provider as BaseProvider);
|
|
} else {
|
|
console.log("Please install MetaMask!");
|
|
}
|
|
});
|
|
```
|
|
|
|
#### Withdraw
|
|
|
|
```ts
|
|
orionUnit.exchange.withdraw({
|
|
amount: 435.275,
|
|
asset: "USDT",
|
|
signer: wallet, // or signer when UI
|
|
});
|
|
```
|
|
|
|
#### Deposit
|
|
|
|
```ts
|
|
orionUnit.exchange.deposit({
|
|
amount: 2.5,
|
|
asset: "ORN",
|
|
signer: wallet, // or signer when UI
|
|
});
|
|
```
|
|
|
|
#### Make swap market
|
|
|
|
```ts
|
|
orionUnit.exchange
|
|
.swapMarket({
|
|
type: "exactSpend",
|
|
assetIn: "ORN",
|
|
assetOut: "USDT",
|
|
feeAsset: "ORN",
|
|
amount: 23.89045345,
|
|
slippagePercent: 1,
|
|
signer: wallet, // or signer when UI
|
|
options: {
|
|
// All options are optional 🙂
|
|
poolOnly: true, // You can specify whether you want to perform the exchange only through the pool
|
|
logger: console.log,
|
|
// Set it to true if you want the issues associated with
|
|
// the lack of allowance to be automatically corrected
|
|
autoApprove: true,
|
|
},
|
|
})
|
|
.then(console.log);
|
|
```
|
|
|
|
#### Add liquidity
|
|
|
|
```ts
|
|
orionUnit.farmingManager.addLiquidity({
|
|
poolName: "ORN-USDT",
|
|
amountAsset: "ORN", // ORN or USDT for this pool
|
|
amount: 23.352345,
|
|
signer: wallet, // or signer when UI
|
|
});
|
|
```
|
|
|
|
#### Remove all liquidity
|
|
|
|
```ts
|
|
orionUnit.farmingManager.removeAllLiquidity({
|
|
poolName: "ORN-USDT",
|
|
signer: wallet, // or signer when UI
|
|
});
|
|
```
|
|
|
|
## Low level methods
|
|
|
|
## About our fetching system
|
|
|
|
Data fetching is often a pain. Network issue, fetching library errors, server errors, wrong response data. We want to be able to handle all these errors in a human way and be sure that we get the expected data.
|
|
|
|
1. We overcome the limitations of exception handling (for example, in the `catch` block, the thrown exception can be anything) with [neverthrow](https://github.com/supermacro/neverthrow).
|
|
2. Predictability (validation) is provided to us by [zod](https://github.com/colinhacks/zod)
|
|
|
|
We have two options for interacting with our services.
|
|
|
|
1. [**Verbose**](./src/fetchWithValidation.ts). Provides a result object that can be successful or not. Provides data to handle fetching error: http code, http status, response body, response status and .etc)
|
|
2. [**Simple Fetch**](./src/simpleFetch.ts). Is a wrapper over a verbose way. Allows you to "just fetch" (perhaps as you usually do)
|
|
|
|
```ts
|
|
// Verbose way example
|
|
|
|
const getCandlesResult = await orionUnit.priceFeed.getCandles(
|
|
"ORN-USDT",
|
|
1650287678,
|
|
1650374078,
|
|
"5m"
|
|
);
|
|
if (getCandlesResult.isErr()) {
|
|
// You can handle fetching errors here
|
|
// You can access error text, statuses
|
|
const { error } = placeOrderFetchResult;
|
|
switch (error.type) {
|
|
case "fetchError": // Instance of Error
|
|
console.error(error.message);
|
|
break;
|
|
case "unknownFetchError":
|
|
console.error(`URL: ${error.url}, Error: ${error.message}`);
|
|
break;
|
|
case "unknownFetchThrow":
|
|
console.error("Something wrong happened during fetching", error.error);
|
|
break;
|
|
// ... more error types see in src/fetchWithValidation.ts
|
|
}
|
|
} else {
|
|
// Success result
|
|
const { candles, timeStart, timeEnd } = getCandlesResult.value;
|
|
// Here we can handle response data
|
|
}
|
|
```
|
|
|
|
```ts
|
|
// Simple Fetch
|
|
|
|
const { candles, timeStart, timeEnd } = await simpleFetch(
|
|
orionUnit.priceFeed.getCandles
|
|
)("ORN-USDT", 1650287678, 1650374078, "5m");
|
|
|
|
// Here we can handle response data
|
|
```
|
|
|
|
### Get historical price
|
|
|
|
```ts
|
|
import { simpleFetch } from "@orionprotocol/sdk";
|
|
|
|
const candles = await simpleFetch(orionUnit.priceFeed.getCandles)(
|
|
"ORN-USDT",
|
|
1650287678, // interval start, unix timestamp
|
|
1650374078, // interval end, unix timestamp
|
|
"5m" // '5m' or '30m' or '1h' or '1d',
|
|
);
|
|
```
|
|
|
|
### Using contracts
|
|
|
|
```ts
|
|
import {
|
|
Exchange__factory,
|
|
ERC20__factory,
|
|
OrionGovernance__factory,
|
|
OrionVoting__factory,
|
|
} from "@orionprotocol/contracts";
|
|
|
|
const exchangeContract = Exchange__factory.connect(
|
|
exchangeContractAddress,
|
|
orionUnit.provider
|
|
);
|
|
const erc20Contract = ERC20__factory.connect(tokenAddress, orionUnit.provider);
|
|
const governanceContract = OrionGovernance__factory.connect(
|
|
governanceAddress,
|
|
orionUnit.provider
|
|
);
|
|
const orionVoting = OrionVoting__factory.connect(
|
|
votingContractAddress,
|
|
orionUnit.provider
|
|
);
|
|
```
|
|
|
|
### Get tradable pairs
|
|
|
|
```ts
|
|
import { simpleFetch } from "@orionprotocol/sdk";
|
|
const pairsList = await simpleFetch(orionUnit.orionAggregator.getPairsList)();
|
|
console.log(pairsList); // ['ORN-USDT', 'BNB-ORN', 'FTM-ORN', 'ETH-ORN']
|
|
```
|
|
|
|
### Get swap info
|
|
|
|
```ts
|
|
import { simpleFetch } from "@orionprotocol/sdk";
|
|
|
|
const swapInfo = await simpleFetch(orionUnit.orionAggregator.getSwapInfo)(
|
|
// Use 'exactSpend' when 'amount' is how much you want spend. Use 'exactReceive' otherwise
|
|
"exactSpend", // type
|
|
"ORN", // asset in
|
|
"USDT", // asset out
|
|
25.23453457, // amount
|
|
["ORION_POOL"] // Exchanges. OPTIONAL! Specify ['ORION_POOL'] if you want "pool only" swap execution
|
|
);
|
|
```
|
|
|
|
Swap info eesponse example:
|
|
|
|
```json
|
|
{
|
|
"id": "2275c9b1-5c42-40c4-805f-bb1e685029f9",
|
|
"assetIn": "ORN",
|
|
"amountIn": 25.23453457,
|
|
"assetOut": "USDT",
|
|
"amountOut": 37.11892965,
|
|
"price": 1.47095757,
|
|
"marketAmountOut": 37.11892965,
|
|
"marketAmountIn": null,
|
|
"marketPrice": 1.47095757,
|
|
"minAmountIn": 8.2,
|
|
"minAmountOut": 12,
|
|
"availableAmountIn": 25.2,
|
|
"availableAmountOut": null, // Null when type is 'exactSpend'
|
|
"path": ["ORN", "USDT"],
|
|
"isThroughPoolOptimal": true,
|
|
"orderInfo": {
|
|
"assetPair": "ORN-USDT",
|
|
"side": "SELL",
|
|
"amount": 25.2,
|
|
"safePrice": 1.468
|
|
},
|
|
"executionInfo": "ORION_POOL: ORN -> USDT (length = 1): 25.23453457 ORN -> 37.11892965 USDT, market amount out = 37.11892965 USDT, price = 1.47095757 USDT/ORN (order SELL 25.2 @ 1.47 (safe price 1.468) on ORN-USDT), available amount in = 25.2 ORN, steps: {[1]: 25.23453457 ORN -> 37.11892965 USDT, price = 1.47095757 USDT/ORN, passed amount in = 25.23453457 ORN, amount out = cost of SELL on ORN-USDT order by min price = 1.47095757 USDT/ORN (sell by amount), avgWeighedPrice = 1.47095757 USDT/ORN, cost by avgWeighedPrice = 37.11892965 USDT, executed sell amount = 25.23453457 ORN}"
|
|
}
|
|
```
|
|
|
|
### Place order in Orion Aggregator
|
|
|
|
```ts
|
|
import { simpleFetch, crypt } from "@orionprotocol/sdk";
|
|
import { crypt } from "@orionprotocol/sdk";
|
|
|
|
const myAddress = await signer.getAddress(); // or wallet.address (without await)
|
|
const {
|
|
matcherAddress, // The address that will transfer funds to you during the exchange process
|
|
} = await simpleFetch(orionUnit.orionBlockchain.getInfo)();
|
|
const baseAssetAddress = "0xfbcad2c3a90fbd94c335fbdf8e22573456da7f68";
|
|
const quoteAssetAddress = "0xcb2951e90d8dcf16e1fa84ac0c83f48906d6a744";
|
|
const amount = "345.623434";
|
|
const price = "2.55";
|
|
const feeAssetAddress = "0xf223eca06261145b3287a0fefd8cfad371c7eb34";
|
|
const fee = "0.7235"; // Orion Fee + Network Fee in fee asset
|
|
const side = "BUY"; // or 'SELL'
|
|
const isPersonalSign = false; // https://docs.metamask.io/guide/signing-data.html#a-brief-history
|
|
const { chainId } = orionUnit;
|
|
|
|
const signedOrder = await crypt.signOrder(
|
|
baseAssetAddress,
|
|
quoteAssetAddress,
|
|
side,
|
|
price,
|
|
amount,
|
|
fee,
|
|
myAddress,
|
|
matcherAddress,
|
|
feeAssetAddress,
|
|
isPersonalSign,
|
|
wallet, // or signer when UI
|
|
chainId
|
|
);
|
|
const exchangeContract = Exchange__factory.connect(
|
|
exchangeContractAddress,
|
|
orionUnit.provider
|
|
);
|
|
|
|
const orderIsOk = await exchangeContract.validateOrder(signedOrder);
|
|
|
|
const { orderId } = await simpleFetch(orionUnit.orionAggregator.placeOrder)(
|
|
signedOrder,
|
|
false // Place in internal orderbook
|
|
);
|
|
```
|
|
|
|
### Orion Aggregator WebSocket
|
|
|
|
Available subscriptions:
|
|
|
|
```ts
|
|
ADDRESS_UPDATES_SUBSCRIBE = 'aus', // Orders history, balances info
|
|
SWAP_SUBSCRIBE = 'ss', // Swap info updates
|
|
AGGREGATED_ORDER_BOOK_UPDATES_SUBSCRIBE = 'aobus', // Bids and asks
|
|
ASSET_PAIRS_CONFIG_UPDATES_SUBSCRIBE = 'apcus',
|
|
BROKER_TRADABLE_ATOMIC_SWAP_ASSETS_BALANCE_UPDATES_SUBSCRIBE = 'btasabus', // Need for Orion Bridge
|
|
```
|
|
|
|
### Swap Info
|
|
|
|
```ts
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
const swapRequestId = uuidv4();
|
|
orionUnit.orionAggregator.ws.subscribe(
|
|
"ss", // SWAP_SUBSCRIBE
|
|
{
|
|
payload: {
|
|
d: swapRequestId, // generated by client
|
|
i: assetIn, // asset in
|
|
o: assetOut, // asset out
|
|
e: true, // true when type of swap is exactSpend, can be omitted (true by default)
|
|
es: ['ORION_POOL'] // OPTIONAL! Specify ['ORION_POOL'] if you want "pool only" swap execution
|
|
a: 5.62345343, // amount
|
|
},
|
|
// Handle data update in your way
|
|
callback: (swapInfo) => {
|
|
switch (swapInfo.kind) {
|
|
case "exactSpend":
|
|
console.log(swapInfo.availableAmountIn);
|
|
break;
|
|
case "exactReceive":
|
|
console.log(swapInfo.availableAmountOut);
|
|
break;
|
|
}
|
|
},
|
|
}
|
|
);
|
|
```
|
|
|
|
### Balances and order history stream
|
|
|
|
```ts
|
|
orionUnit.orionAggregator.ws.subscribe(
|
|
"aus", // ADDRESS_UPDATES_SUBSCRIBE — orders, balances
|
|
{
|
|
payload: "0x0000000000000000000000000000000000000000", // Some wallet address
|
|
callback: (data) => {
|
|
switch (data.kind) {
|
|
case "initial":
|
|
if (data.orders) console.log(data.orders); // All orders. "orders" is undefined if you don't have any orders yet
|
|
console.log(data.balances); // Since this is initial message, the balances contain all assets
|
|
break;
|
|
case "update": {
|
|
if (data.order) {
|
|
switch (data.order.kind) {
|
|
case "full":
|
|
console.log("Pool order", data.order); // Orders from the pool go into history with the SETTLED status
|
|
break;
|
|
case "update":
|
|
console.log("Order in the process of execution", data.order);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (data.balances) console.log("Balance update", data.balances); // Since this is an update message, the balances only contain the changed assets
|
|
}
|
|
}
|
|
},
|
|
}
|
|
);
|
|
```
|
|
|
|
### Orderbook stream
|
|
|
|
```ts
|
|
orionUnit.orionAggregator.ws.subscribe("aobus", {
|
|
payload: "ORN-USDT", // Some trading pair
|
|
callback: (asks, bids, pairName) => {
|
|
console.log(`${pairName} orderbook asks`, asks);
|
|
console.log(`${pairName} orderbook bids`, bids);
|
|
},
|
|
});
|
|
```
|
|
|
|
### Orion Aggregator WS Stream Unsubscribing
|
|
|
|
```ts
|
|
// Swap request unsubscribe
|
|
orionAggregator.ws.unsubscribe(swapRequestId); // Pass here id that you generate when subscribe
|
|
|
|
// Address update (balances / order history) unsubscribe
|
|
orionUnit.orionAggregator.ws.unsubscribe(
|
|
"0x0000000000000000000000000000000000000000"
|
|
);
|
|
|
|
// Pair orderbook unsubscribe
|
|
orionUnit.orionAggregator.ws.unsubscribe("ORN-USDT");
|
|
|
|
// Asset pairs config updates unsubscribe
|
|
orionUnit.orionAggregator.ws.unsubscribe("apcu");
|
|
|
|
// Broker tradable atomic swap assets balance unsubscribe
|
|
orionUnit.orionAggregator.ws.unsubscribe("btasabu");
|
|
```
|
|
|
|
## Price Feed Websocket Stream
|
|
|
|
```ts
|
|
const allTickersSubscription = orionUnit.priceFeed.ws.subscribe("allTickers", {
|
|
callback: (tickers) => {
|
|
console.log(tickers);
|
|
},
|
|
});
|
|
allTickersSubscription.unsubscribe();
|
|
orionUnit.priceFeed.ws.unsubscribe("allTickers", allTickersSubscription.id); // Also you can unsubscribe like this
|
|
|
|
const tickerSubscription = orionUnit.priceFeed.ws.subscribe("ticker", {
|
|
callback: (ticker) => {
|
|
console.log(tricker);
|
|
},
|
|
payload: "ORN-USDT",
|
|
});
|
|
tickerSubscription.subscription();
|
|
orionUnit.priceFeed.ws.unsubscribe("ticker", tickerSubscription.id);
|
|
|
|
const lastPriceSubscription = orionUnit.priceFeed.ws.subscribe("lastPrice", {
|
|
callback: ({ pair, price }) => {
|
|
console.log(`Price: ${price}`);
|
|
},
|
|
payload: "ORN-USDT",
|
|
});
|
|
lastPriceSubscription.unsubscribe();
|
|
orionUnit.priceFeed.ws.unsubscribe("lastPrice", lastPriceSubscription.id);
|
|
```
|