mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-13 21:52:36 +03:00
added PMM-sample.md , fixed order schema
This commit is contained in:
288
PMM-sample.md
Normal file
288
PMM-sample.md
Normal file
@@ -0,0 +1,288 @@
|
||||
<!-- Insert logo -->
|
||||
|
||||
<div align="center">
|
||||
<img
|
||||
src="./logo.svg"
|
||||
width="300"
|
||||
alt="Orion Protocol SDK logo"
|
||||
/>
|
||||
<h1>PMM example</h1>
|
||||
</div>
|
||||
|
||||
## Overview
|
||||
|
||||
This is special example which shows how to use PMM liquidity without using SDK, only using few libraries
|
||||
|
||||
```ts
|
||||
import {ethers, Wallet} from "ethers";
|
||||
import {z} from "zod";
|
||||
import hmacSHA256 from "crypto-js/hmac-sha256";
|
||||
import Hex from "crypto-js/enc-hex";
|
||||
|
||||
///////////////////////////////
|
||||
///////////////////////////////
|
||||
const pmmOrderQuotationSchema = z.object({
|
||||
info: z.string().default(''),
|
||||
makerAsset: z.string().default(''),
|
||||
takerAsset: z.string().default(''),
|
||||
maker: z.string().default(''),
|
||||
allowedSender: z.string().default(''),
|
||||
makingAmount: z.string().default(''),
|
||||
takingAmount: z.string().default(''),
|
||||
});
|
||||
|
||||
const pmmOrderSchema = z.object({
|
||||
order: pmmOrderQuotationSchema.default({}),
|
||||
signature: z.string().default(''),
|
||||
success: z.boolean().default(false),
|
||||
error: z.string().default(''),
|
||||
});
|
||||
|
||||
const orionRFQContractABI =
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "info",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "makerAsset",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "takerAsset",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "maker",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "allowedSender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "makingAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "takingAmount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"internalType": "struct OrderRFQLib.OrderRFQ",
|
||||
"name": "order",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "signature",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "flagsAndAmount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "fillOrderRFQ",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
];
|
||||
|
||||
function encode_utf8(s : string) {
|
||||
return unescape(encodeURIComponent(s));
|
||||
}
|
||||
function sign(message : string, key: string) {
|
||||
return hmacSHA256(
|
||||
encode_utf8(message),
|
||||
encode_utf8(key)
|
||||
).toString(Hex);
|
||||
}
|
||||
|
||||
function generateHeaders(body : any, method : string, path : string, timestamp : number, apiKey : string, secretKey : string) {
|
||||
const sortedBody = Object.keys(body)
|
||||
.sort()
|
||||
.map((key) => (
|
||||
`${key}=${body[key]}`
|
||||
)).join('&');
|
||||
|
||||
const payload = timestamp + method.toUpperCase() + path + sortedBody;
|
||||
|
||||
const signature = sign(payload, secretKey);
|
||||
|
||||
const httpOptions = {
|
||||
headers: {
|
||||
'API-KEY': apiKey,
|
||||
'ACCESS-TIMESTAMP': timestamp.toString(),
|
||||
'ACCESS-SIGN': signature
|
||||
}
|
||||
};
|
||||
return httpOptions;
|
||||
}
|
||||
|
||||
//
|
||||
async function RFQOrder(
|
||||
tokenFrom: string,
|
||||
tokenTo: string,
|
||||
fromTokenAmount: string,
|
||||
apiKey: string, //
|
||||
secretKey: string,
|
||||
wallet: string
|
||||
) : Promise<z.infer<typeof pmmOrderSchema>> {
|
||||
|
||||
// NB: replace with correct URL for networks
|
||||
const apiUrl = 'https://testing.orion.xyz/bsc-testnet/backend'
|
||||
// const apiUrl = 'https://trade.orion.xyz/bsc-mainnet/backend'
|
||||
, path = '/rfq'
|
||||
, url = `${apiUrl}/api/v1/integration/pmm`+path
|
||||
, headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
, data = {
|
||||
"baseToken":tokenFrom, // USDT
|
||||
"quoteToken":tokenTo, // ORN
|
||||
"amount": fromTokenAmount, // 100
|
||||
"taker": wallet,
|
||||
"feeBps": 0
|
||||
}
|
||||
, method = 'POST'
|
||||
, timestamp = Date.now()
|
||||
, signatureHeaders = generateHeaders(data, method, path, timestamp, apiKey, secretKey)
|
||||
, compiledHeaders = {...headers, ...signatureHeaders.headers, }
|
||||
, body = JSON.stringify(data)
|
||||
;
|
||||
|
||||
let res = pmmOrderSchema.parse({});
|
||||
|
||||
try {
|
||||
const result = await fetch(url,{
|
||||
headers: compiledHeaders,
|
||||
method,
|
||||
body
|
||||
});
|
||||
|
||||
// const data = await result.text();
|
||||
// console.log(data);
|
||||
|
||||
const json = await result.json();
|
||||
console.log(json);
|
||||
const parseResult = pmmOrderSchema.safeParse(json);
|
||||
|
||||
if(!parseResult.success) {
|
||||
// Try to parse error answer
|
||||
const errorSchema = z.object({error: z.object({code: z.number(), reason: z.string()})});
|
||||
|
||||
const errorParseResult = errorSchema.safeParse(json);
|
||||
|
||||
if(!errorParseResult.success)
|
||||
throw Error(`Unrecognized answer from aggregator: ${json}`);
|
||||
|
||||
throw Error(errorParseResult.data.error.reason);
|
||||
}
|
||||
|
||||
res.order = parseResult.data.order;
|
||||
res.signature = parseResult.data.signature;
|
||||
res.error = '';
|
||||
res.success = true;
|
||||
}
|
||||
catch(err) {
|
||||
res.error = `${err}`;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
(async() => {
|
||||
const apiKey = '958153f1-b8b9-3ec4-84eb-2147429105d9';
|
||||
const secretKey = 'secretKey';
|
||||
|
||||
// BNB testnet tokens and router
|
||||
const assetORN = '0xf223eca06261145b3287a0fefd8cfad371c7eb34';
|
||||
const assetUSDT = '0xcb2951e90d8dcf16e1fa84ac0c83f48906d6a744';
|
||||
const router = '0x89357522C0ed6E557D39dC75290859246077bdfC';
|
||||
|
||||
// BNB mainnet tokens and router
|
||||
// const assetORN = '0xe4ca1f75eca6214393fce1c1b316c237664eaa8e';
|
||||
// const assetUSDT = '0x55d398326f99059ff775485246999027b3197955';
|
||||
// const router = '0xcb2D40EabC4f4c92Ee993Eb3D67f7717bE476E76';
|
||||
|
||||
const rfqOrder = await RFQOrder(
|
||||
assetORN, // Spending asset
|
||||
assetUSDT, // Receiving asset
|
||||
'1000000000', // Amount in "satoshi" of spending asset
|
||||
apiKey,
|
||||
secretKey,
|
||||
'0x61Eed69c0d112C690fD6f44bB621357B89fBE67F' // Can be any address, ignored for now
|
||||
);
|
||||
|
||||
if(!rfqOrder.success) {
|
||||
console.log(rfqOrder.error);
|
||||
return;
|
||||
}
|
||||
|
||||
// ... here you can check order prices, etc.
|
||||
console.log(rfqOrder);
|
||||
|
||||
// Calldata according to provided rfqOrder
|
||||
const contractInterface = new ethers.Interface(orionRFQContractABI);
|
||||
const calldata = contractInterface.encodeFunctionData("fillOrderRFQ", [rfqOrder.order, rfqOrder.signature, 0]);
|
||||
console.log('Calldata = ', calldata);
|
||||
|
||||
// Call router with this data
|
||||
// Replace with your private key
|
||||
const yourWalletPrivateKey = '0xf1.......';
|
||||
|
||||
const tx = {
|
||||
to: router,
|
||||
data: calldata
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider("https://data-seed-prebsc-1-s1.binance.org:8545/");
|
||||
const signer = new ethers.Wallet(yourWalletPrivateKey, provider);
|
||||
console.log('Address = ', signer.address);
|
||||
const transactionResponse = await signer.sendTransaction(tx);
|
||||
console.log("Transaction hash:", transactionResponse.hash);
|
||||
await transactionResponse.wait();
|
||||
})();
|
||||
```
|
||||
|
||||
RFQ order response example description (`rfqOrder` from example above):
|
||||
|
||||
```
|
||||
{
|
||||
quotation: {
|
||||
info: '31545611720730315633520017429',
|
||||
makerAsset: '0xcb2951e90d8dcf16e1fa84ac0c83f48906d6a744',
|
||||
takerAsset: '0xf223eca06261145b3287a0fefd8cfad371c7eb34',
|
||||
maker: '0x1ff516e5ce789085cff86d37fc27747df852a80a',
|
||||
allowedSender: '0x0000000000000000000000000000000000000000',
|
||||
makingAmount: '193596929',
|
||||
takingAmount: '10000000000'
|
||||
},
|
||||
signature: '0x8a2f9140a3c3a5734eda763a19c54c5ac909d8a03db37d9804af9115641fd1d35896b66ca6e136c1c89e0478fb7382a4b875d0f74529c1e83601f9383d310dde1b',
|
||||
success: true,
|
||||
error: ''
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
* info - can be ignored
|
||||
* makerAsset - your RECEIVING asset (what you expect to receive from contract, in this case USDT)
|
||||
* takerAsset - your SPENDING asset (what you're giving to contract, in this case ORN)
|
||||
* maker - can be ignored for now;
|
||||
* allowedSender - can be ignored for now;
|
||||
* makingAmount - how much you will RECEIVE (in receiving asset's precision)
|
||||
* takingAmount - how much you should SPEND (in spending asset's precision)
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@orionprotocol/sdk",
|
||||
"version": "0.20.68-rc1",
|
||||
"version": "0.20.79-rc1",
|
||||
"description": "Orion Protocol SDK",
|
||||
"main": "./lib/index.cjs",
|
||||
"module": "./lib/index.js",
|
||||
|
||||
@@ -79,6 +79,6 @@ export default class Pmm {
|
||||
const contract = new ethers.Contract(this.contractAddress, orionRFQContractABI, signer);
|
||||
|
||||
// @ts-ignore
|
||||
return contract.fillOrderRFQ(order.quotation, order.signature, BigInt(0));
|
||||
return contract.fillOrderRFQ(order.order, order.signature, BigInt(0));
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ export const pmmOrderQuotationSchema = z.object({
|
||||
});
|
||||
|
||||
export const pmmOrderSchema = z.object({
|
||||
quotation: pmmOrderQuotationSchema.default({}),
|
||||
order: pmmOrderQuotationSchema.default({}),
|
||||
signature: z.string().default(''),
|
||||
success: z.boolean().default(false),
|
||||
error: z.string().default(''),
|
||||
|
||||
@@ -461,11 +461,10 @@ class Aggregator {
|
||||
throw Error(errorParseResult.data.error.reason);
|
||||
}
|
||||
|
||||
res.quotation = parseResult.data.quotation;
|
||||
res.order = parseResult.data.order;
|
||||
res.signature = parseResult.data.signature;
|
||||
res.error = '';
|
||||
res.success = true;
|
||||
// return result;
|
||||
}
|
||||
catch(err) {
|
||||
res.error = `${err}`;
|
||||
|
||||
Reference in New Issue
Block a user