mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-29 09:07:59 +03:00
Added array schema failover / PF onOpen / bridge test / deps bump
This commit is contained in:
1205
package-lock.json
generated
1205
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@orionprotocol/sdk",
|
||||
"version": "0.17.26",
|
||||
"version": "0.17.27",
|
||||
"description": "Orion Protocol SDK",
|
||||
"main": "./lib/esm/index.js",
|
||||
"module": "./lib/esm/index.js",
|
||||
@@ -42,14 +42,14 @@
|
||||
"@tsconfig/strictest": "^1.0.2",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "^18.14.0",
|
||||
"@types/node": "^18.14.6",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/socket.io-client": "1.4.33",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@types/ws": "^8.5.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||
"@typescript-eslint/parser": "^5.53.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"@babel/core": "^7.21.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"concurrently": "^7.6.0",
|
||||
"eslint": "^8.34.0",
|
||||
@@ -70,11 +70,11 @@
|
||||
"webpack-cli": "^5.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@ethersproject/abstract-signer": "^5.7.0",
|
||||
"@ethersproject/providers": "^5.7.2",
|
||||
"@lukeed/csprng": "^1.0.1",
|
||||
"@orionprotocol/contracts": "0.2.2",
|
||||
"@orionprotocol/contracts": "0.3.0",
|
||||
"bignumber.js": "^9.1.1",
|
||||
"bson-objectid": "^2.0.4",
|
||||
"buffer": "^6.0.3",
|
||||
@@ -92,7 +92,7 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"uuid": "^9.0.0",
|
||||
"ws": "^8.12.1",
|
||||
"zod": "^3.20.6"
|
||||
"zod": "^3.21.2"
|
||||
},
|
||||
"homepage": "https://github.com/orionprotocol/sdk#readme",
|
||||
"files": [
|
||||
|
||||
@@ -102,7 +102,7 @@ export default async function swap({
|
||||
|
||||
const sourceChainNativeCryptocurrency = getNativeCryptocurrency(sourceAssetToAddress);
|
||||
const sourceExchangeContract = Exchange__factory.connect(sourceExchangeContractAddress, sourceProvider);
|
||||
const sourceChainGasPriceWei = await simpleFetch(sourceOrionBlockchain.getGasPriceWei)();
|
||||
// const sourceChainGasPriceWei = await simpleFetch(sourceOrionBlockchain.getGasPriceWei)();
|
||||
|
||||
const sourceChainAssetAddress = sourceAssetToAddress[assetName];
|
||||
if (sourceChainAssetAddress === undefined) throw new Error(`Asset '${assetName}' not found in source chain`);
|
||||
@@ -197,8 +197,23 @@ export default async function swap({
|
||||
targetChainId: ethers.BigNumber.from(targetChain),
|
||||
});
|
||||
|
||||
let sourceChainGasPrice: ethers.BigNumber;
|
||||
const sourceChainFeeData = await sourceChainOrionUnit.provider.getFeeData();
|
||||
if (ethers.BigNumber.isBigNumber(sourceChainFeeData.gasPrice)) { //
|
||||
unsignedLockAtomicTx.gasPrice = sourceChainFeeData.gasPrice;
|
||||
sourceChainGasPrice = sourceChainFeeData.gasPrice;
|
||||
} else if (
|
||||
ethers.BigNumber.isBigNumber(sourceChainFeeData.maxFeePerGas) &&
|
||||
ethers.BigNumber.isBigNumber(sourceChainFeeData.maxPriorityFeePerGas)
|
||||
) { // EIP-1559
|
||||
unsignedLockAtomicTx.maxFeePerGas = sourceChainFeeData.maxFeePerGas;
|
||||
unsignedLockAtomicTx.maxPriorityFeePerGas = sourceChainFeeData.maxPriorityFeePerGas;
|
||||
sourceChainGasPrice = sourceChainFeeData.maxFeePerGas;
|
||||
} else {
|
||||
throw new Error('Can\'t get gas price');
|
||||
}
|
||||
|
||||
unsignedLockAtomicTx.chainId = parseInt(chainId, 10);
|
||||
unsignedLockAtomicTx.gasPrice = ethers.BigNumber.from(sourceChainGasPriceWei);
|
||||
unsignedLockAtomicTx.from = walletAddress;
|
||||
|
||||
let value = new BigNumber(0);
|
||||
@@ -214,7 +229,7 @@ export default async function swap({
|
||||
);
|
||||
unsignedLockAtomicTx.gasLimit = ethers.BigNumber.from(LOCKATOMIC_GAS_LIMIT);
|
||||
|
||||
const transactionCost = ethers.BigNumber.from(LOCKATOMIC_GAS_LIMIT).mul(sourceChainGasPriceWei);
|
||||
const transactionCost = ethers.BigNumber.from(LOCKATOMIC_GAS_LIMIT).mul(sourceChainGasPrice);
|
||||
const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION);
|
||||
|
||||
sourceChainBalanceGuard.registerRequirement({
|
||||
@@ -261,7 +276,7 @@ export default async function swap({
|
||||
|
||||
options?.logger?.('Atomic swap placed.');
|
||||
|
||||
const targetChainGasPriceWei = await simpleFetch(targetOrionBlockchain.getGasPriceWei)();
|
||||
// const targetChainGasPriceWei = await simpleFetch(targetOrionBlockchain.getGasPriceWei)();
|
||||
const unsignedRedeemAtomicTx = await targetExchangeContract.populateTransaction.redeemAtomic(
|
||||
{
|
||||
amount: amountBlockchainParam,
|
||||
@@ -276,13 +291,28 @@ export default async function swap({
|
||||
secret
|
||||
)
|
||||
|
||||
let targetChainGasPrice: ethers.BigNumber;
|
||||
const targetChainFeeData = await targetChainOrionUnit.provider.getFeeData();
|
||||
if (ethers.BigNumber.isBigNumber(targetChainFeeData.gasPrice)) { //
|
||||
unsignedRedeemAtomicTx.gasPrice = targetChainFeeData.gasPrice;
|
||||
targetChainGasPrice = targetChainFeeData.gasPrice;
|
||||
} else if (
|
||||
ethers.BigNumber.isBigNumber(targetChainFeeData.maxFeePerGas) &&
|
||||
ethers.BigNumber.isBigNumber(targetChainFeeData.maxPriorityFeePerGas)
|
||||
) { // EIP-1559
|
||||
unsignedRedeemAtomicTx.maxFeePerGas = targetChainFeeData.maxFeePerGas;
|
||||
unsignedRedeemAtomicTx.maxPriorityFeePerGas = targetChainFeeData.maxPriorityFeePerGas;
|
||||
targetChainGasPrice = targetChainFeeData.maxFeePerGas;
|
||||
} else {
|
||||
throw new Error('Can\'t get gas price');
|
||||
}
|
||||
|
||||
unsignedRedeemAtomicTx.chainId = parseInt(targetChain, 10);
|
||||
unsignedRedeemAtomicTx.gasPrice = ethers.BigNumber.from(targetChainGasPriceWei);
|
||||
unsignedRedeemAtomicTx.from = walletAddress;
|
||||
unsignedRedeemAtomicTx.gasLimit = ethers.BigNumber.from(REDEEMATOMIC_GAS_LIMIT);
|
||||
|
||||
const targetTransactionCost = ethers.BigNumber.from(REDEEMATOMIC_GAS_LIMIT).mul(targetChainGasPriceWei);
|
||||
const targetDenormalizedTransactionCost = denormalizeNumber(targetTransactionCost, NATIVE_CURRENCY_PRECISION);
|
||||
const redeemAtomicTransactionCost = ethers.BigNumber.from(REDEEMATOMIC_GAS_LIMIT).mul(targetChainGasPrice);
|
||||
const targetDenormalizedTransactionCost = denormalizeNumber(redeemAtomicTransactionCost, NATIVE_CURRENCY_PRECISION);
|
||||
|
||||
targetChainBalanceGuard.registerRequirement({
|
||||
reason: 'Network fee',
|
||||
@@ -314,8 +344,21 @@ export default async function swap({
|
||||
targetChainAssetAddress,
|
||||
amountBlockchainParam,
|
||||
);
|
||||
if (ethers.BigNumber.isBigNumber(targetChainFeeData.gasPrice)) { //
|
||||
unsignedWithdrawTx.gasPrice = targetChainFeeData.gasPrice;
|
||||
targetChainGasPrice = targetChainFeeData.gasPrice;
|
||||
} else if (
|
||||
ethers.BigNumber.isBigNumber(targetChainFeeData.maxFeePerGas) &&
|
||||
ethers.BigNumber.isBigNumber(targetChainFeeData.maxPriorityFeePerGas)
|
||||
) { // EIP-1559
|
||||
unsignedWithdrawTx.maxFeePerGas = targetChainFeeData.maxFeePerGas;
|
||||
unsignedWithdrawTx.maxPriorityFeePerGas = targetChainFeeData.maxPriorityFeePerGas;
|
||||
targetChainGasPrice = targetChainFeeData.maxFeePerGas;
|
||||
} else {
|
||||
throw new Error('Can\'t get gas price');
|
||||
}
|
||||
unsignedWithdrawTx.chainId = parseInt(targetChain, 10);
|
||||
unsignedWithdrawTx.gasLimit = ethers.BigNumber.from(WITHDRAW_GAS_LIMIT);
|
||||
unsignedWithdrawTx.gasPrice = ethers.BigNumber.from(targetChainGasPriceWei);
|
||||
unsignedWithdrawTx.from = walletAddress;
|
||||
unsignedWithdrawTx.nonce = await targetProvider.getTransactionCount(walletAddress, 'pending');
|
||||
const signedTx = await signer.signTransaction(unsignedWithdrawTx);
|
||||
|
||||
28
src/__tests__/bridge.test.ts
Normal file
28
src/__tests__/bridge.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Wallet } from 'ethers';
|
||||
import Orion from '../Orion';
|
||||
import { SupportedChainId } from '../types';
|
||||
|
||||
const privateKey = process.env['PRIVATE_KEY']
|
||||
if (privateKey === undefined) throw new Error('Private key is required');
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
describe('Bridge', () => {
|
||||
test('Execution', async () => {
|
||||
const orion = new Orion('testing');
|
||||
const wallet = new Wallet(privateKey);
|
||||
|
||||
await orion.bridge.swap(
|
||||
'ORN',
|
||||
0.12345678,
|
||||
SupportedChainId.FANTOM_TESTNET,
|
||||
SupportedChainId.BSC_TESTNET,
|
||||
wallet,
|
||||
{
|
||||
autoApprove: true,
|
||||
logger: console.log,
|
||||
withdrawToWallet: true,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,6 @@
|
||||
import { ethers } from 'ethers';
|
||||
import { z } from 'zod';
|
||||
import getValidArrayItemsSchema from '../../../utils/getValidArrayItems';
|
||||
|
||||
const baseAtomicHistorySchema = z.object({
|
||||
success: z.boolean(),
|
||||
@@ -14,9 +16,9 @@ const baseAtomicHistoryItem = z.object({
|
||||
_id: z.string(),
|
||||
__v: z.number(),
|
||||
asset: z.string(),
|
||||
sender: z.string(),
|
||||
secretHash: z.string(),
|
||||
receiver: z.string().optional(),
|
||||
sender: z.string().refine(ethers.utils.isAddress),
|
||||
secretHash: z.string().refine(ethers.utils.isHexString),
|
||||
receiver: z.string().refine(ethers.utils.isAddress).optional(),
|
||||
secret: z.string().optional(),
|
||||
});
|
||||
|
||||
@@ -64,7 +66,7 @@ export const targetAtomicHistorySchema = baseAtomicHistorySchema.extend({
|
||||
});
|
||||
|
||||
const atomicHistorySchema = baseAtomicHistorySchema.extend({
|
||||
data: z.array(
|
||||
data: getValidArrayItemsSchema(
|
||||
z.discriminatedUnion('type', [sourceAtomicHistorySchemaItem, targetAtomicHistorySchemaItem]),
|
||||
),
|
||||
});
|
||||
|
||||
@@ -85,10 +85,13 @@ export default class PriceFeedSubscription<T extends SubscriptionType = Subscrip
|
||||
// https://stackoverflow.com/questions/19304157/getting-the-reason-why-websockets-closed-with-close-code-1006
|
||||
private isClosedIntentionally = false;
|
||||
|
||||
private readonly onOpen: ((event: WebSocket.Event) => void) | undefined;
|
||||
|
||||
constructor(
|
||||
type: T,
|
||||
url: string,
|
||||
params: Subscription<T>,
|
||||
onOpen?: (event: WebSocket.Event) => void,
|
||||
) {
|
||||
this.id = uuidv4();
|
||||
this.url = url;
|
||||
@@ -97,7 +100,7 @@ export default class PriceFeedSubscription<T extends SubscriptionType = Subscrip
|
||||
this.payload = params.payload;
|
||||
}
|
||||
this.callback = params.callback;
|
||||
|
||||
this.onOpen = onOpen;
|
||||
this.init();
|
||||
}
|
||||
|
||||
@@ -118,6 +121,9 @@ export default class PriceFeedSubscription<T extends SubscriptionType = Subscrip
|
||||
const { payload, url, type } = this;
|
||||
this.ws = new WebSocket(`${url}/${type}${payload !== undefined ? `/${payload.toString()}` : ''}`);
|
||||
|
||||
if (this.onOpen !== undefined) {
|
||||
this.ws.onopen = this.onOpen;
|
||||
}
|
||||
this.ws.onmessage = (e) => {
|
||||
const { data } = e;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type WebSocket from 'ws';
|
||||
import PriceFeedSubscription, { type SubscriptionType, type Subscription } from './PriceFeedSubscription';
|
||||
|
||||
export * as schemas from './schemas';
|
||||
@@ -20,11 +21,13 @@ export class PriceFeedWS {
|
||||
subscribe<S extends SubscriptionType>(
|
||||
type: S,
|
||||
params: Subscription<S>,
|
||||
onOpen?: (event: WebSocket.Event) => void,
|
||||
) {
|
||||
const sub = new PriceFeedSubscription(
|
||||
type,
|
||||
this.url,
|
||||
params,
|
||||
onOpen
|
||||
);
|
||||
this.subscriptions = {
|
||||
...this.subscriptions,
|
||||
|
||||
20
src/utils/getValidArrayItems.ts
Normal file
20
src/utils/getValidArrayItems.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { Schema, ZodTypeDef } from 'zod';
|
||||
import { z } from 'zod'
|
||||
|
||||
export default function getValidArrayItemsSchema<DataOut, Def extends ZodTypeDef, DataIn> (
|
||||
elemSchema: Schema<DataOut, Def, DataIn>,
|
||||
) {
|
||||
return z.array(z.unknown()).transform((items) => {
|
||||
const validItems: Array<z.infer<typeof elemSchema>> = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
const parsedItem = elemSchema.safeParse(item);
|
||||
if (parsedItem.success) {
|
||||
validItems.push(parsedItem.data);
|
||||
} else {
|
||||
console.log(`Array item with index ${i} is invalid. Error: ${parsedItem.error.message}. Data: ${JSON.stringify(item)}.`)
|
||||
}
|
||||
}
|
||||
return validItems;
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user