mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-14 14:12:35 +03:00
7.5 KiB
7.5 KiB
Overview
This is special example which shows how to use PMM liquidity without using SDK, only using few libraries
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();
})();