mirror of
https://github.com/pezkuwichain/pezkuwi-subquery.git
synced 2026-04-21 23:37:56 +00:00
Migrate to native @pezkuwi packages and remove swap integrations
Replace npm aliases (@polkadot -> @pezkuwi) with direct @pezkuwi package imports. Add tsconfig path mappings to redirect @polkadot type references from @subql/types to @pezkuwi equivalents, enabling proper type resolution without installing @polkadot packages. Remove Polkadot ecosystem swap/bridge integrations (HydraDx, AssetConversion) as they're incompatible with Pezkuwi.
This commit is contained in:
+11
-9
@@ -19,15 +19,17 @@
|
|||||||
"author": "Pezkuwi Team",
|
"author": "Pezkuwi Team",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash": "^4.17.21",
|
"@pezkuwi/api": "^16.5.36",
|
||||||
"@polkadot/api": "npm:@pezkuwi/api@^16.5.34",
|
"@pezkuwi/api-augment": "^16.5.36",
|
||||||
"@polkadot/api-derive": "npm:@pezkuwi/api-derive@^16.5.34",
|
"@pezkuwi/api-derive": "^16.5.36",
|
||||||
"@polkadot/types": "npm:@pezkuwi/types@^16.5.34",
|
"@pezkuwi/keyring": "^14.0.25",
|
||||||
"@polkadot/types-augment": "npm:@pezkuwi/types-augment@^16.5.34",
|
"@pezkuwi/types": "^16.5.36",
|
||||||
"@polkadot/types-codec": "npm:@pezkuwi/types-codec@^16.5.34",
|
"@pezkuwi/types-augment": "^16.5.36",
|
||||||
"@polkadot/util": "npm:@pezkuwi/util@^14.0.23",
|
"@pezkuwi/types-codec": "^16.5.36",
|
||||||
"@polkadot/util-crypto": "npm:@pezkuwi/util-crypto@^14.0.23",
|
"@pezkuwi/types-create": "^16.5.36",
|
||||||
"@polkadot/keyring": "npm:@pezkuwi/keyring@^14.0.23"
|
"@pezkuwi/util": "^14.0.25",
|
||||||
|
"@pezkuwi/util-crypto": "^14.0.25",
|
||||||
|
"lodash": "^4.17.21"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@subql/cli": "latest",
|
"@subql/cli": "latest",
|
||||||
|
|||||||
+1
-2
@@ -4,5 +4,4 @@ export * from "./mappings/Rewards";
|
|||||||
export * from "./mappings/PoolRewards";
|
export * from "./mappings/PoolRewards";
|
||||||
export * from "./mappings/Transfers";
|
export * from "./mappings/Transfers";
|
||||||
export * from "./mappings/NewEra";
|
export * from "./mappings/NewEra";
|
||||||
export * from "./mappings/swaps";
|
import "@pezkuwi/api-augment";
|
||||||
import "@polkadot/api-augment";
|
|
||||||
|
|||||||
+16
-31
@@ -1,16 +1,11 @@
|
|||||||
import "@polkadot/types-augment/lookup";
|
|
||||||
import { SubstrateEvent } from "@subql/types";
|
import { SubstrateEvent } from "@subql/types";
|
||||||
import { blockNumber } from "./common";
|
import { blockNumber } from "./common";
|
||||||
import { AccountId } from "@polkadot/types/interfaces";
|
import { Option } from "@pezkuwi/types";
|
||||||
import {
|
import { RewardDestination, AccountId } from "@pezkuwi/types/interfaces";
|
||||||
PalletStakingRewardDestination,
|
|
||||||
PalletNominationPoolsPoolMember,
|
|
||||||
} from "@polkadot/types/lookup";
|
|
||||||
import { Option } from "@polkadot/types";
|
|
||||||
|
|
||||||
// Due to memory consumption optimization `rewardDestinationByAddress` contains only one key
|
// Due to memory consumption optimization `rewardDestinationByAddress` contains only one key
|
||||||
let rewardDestinationByAddress: {
|
let rewardDestinationByAddress: {
|
||||||
[blockId: string]: { [address: string]: PalletStakingRewardDestination };
|
[blockId: string]: { [address: string]: RewardDestination };
|
||||||
} = {};
|
} = {};
|
||||||
let controllersByStash: { [blockId: string]: { [address: string]: string } } =
|
let controllersByStash: { [blockId: string]: { [address: string]: string } } =
|
||||||
{};
|
{};
|
||||||
@@ -18,13 +13,13 @@ let controllersByStash: { [blockId: string]: { [address: string]: string } } =
|
|||||||
let parachainStakingRewardEra: { [blockId: string]: number } = {};
|
let parachainStakingRewardEra: { [blockId: string]: number } = {};
|
||||||
|
|
||||||
let poolMembers: {
|
let poolMembers: {
|
||||||
[blockId: number]: [string, PalletNominationPoolsPoolMember][];
|
[blockId: number]: [string, any][];
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
export async function cachedRewardDestination(
|
export async function cachedRewardDestination(
|
||||||
accountAddress: string,
|
accountAddress: string,
|
||||||
event: SubstrateEvent,
|
event: SubstrateEvent,
|
||||||
): Promise<PalletStakingRewardDestination> {
|
): Promise<RewardDestination> {
|
||||||
const blockId = blockNumber(event);
|
const blockId = blockNumber(event);
|
||||||
let cachedBlock = rewardDestinationByAddress[blockId];
|
let cachedBlock = rewardDestinationByAddress[blockId];
|
||||||
|
|
||||||
@@ -43,7 +38,7 @@ export async function cachedRewardDestination(
|
|||||||
});
|
});
|
||||||
|
|
||||||
let destinationByAddress: {
|
let destinationByAddress: {
|
||||||
[address: string]: PalletStakingRewardDestination;
|
[address: string]: RewardDestination;
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -58,8 +53,7 @@ export async function cachedRewardDestination(
|
|||||||
},
|
},
|
||||||
} = event;
|
} = event;
|
||||||
let accountAddress = accountId.toString();
|
let accountAddress = accountId.toString();
|
||||||
destinationByAddress[accountAddress] =
|
destinationByAddress[accountAddress] = destination as unknown as RewardDestination;
|
||||||
destination as PalletStakingRewardDestination;
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const allAccountsInBlock = allEventsInBlock.map((event) => {
|
const allAccountsInBlock = allEventsInBlock.map((event) => {
|
||||||
@@ -74,26 +68,20 @@ export async function cachedRewardDestination(
|
|||||||
// looks like accountAddress not related to events so just try to query payee directly
|
// looks like accountAddress not related to events so just try to query payee directly
|
||||||
if (allAccountsInBlock.length === 0) {
|
if (allAccountsInBlock.length === 0) {
|
||||||
rewardDestinationByAddress[blockId] = {};
|
rewardDestinationByAddress[blockId] = {};
|
||||||
return (await api.query.staking.payee(
|
return (await api.query.staking.payee(accountAddress)) as unknown as RewardDestination;
|
||||||
accountAddress,
|
|
||||||
)) as unknown as PalletStakingRewardDestination;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Commented code doesn't work now, may be fixed later
|
|
||||||
// const payees = await api.query.staking.payee.multi(allAccountsInBlock);
|
|
||||||
const payees = await api.queryMulti(
|
const payees = await api.queryMulti(
|
||||||
allAccountsInBlock.map((account) => [api.query.staking.payee, account]),
|
allAccountsInBlock.map((account) => [api.query.staking.payee, account]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const rewardDestinations = payees.map((payee) => {
|
const rewardDestinations = payees.map((payee) => {
|
||||||
return payee as PalletStakingRewardDestination;
|
return payee as unknown as RewardDestination;
|
||||||
});
|
});
|
||||||
|
|
||||||
// something went wrong, so just query for single accountAddress
|
// something went wrong, so just query for single accountAddress
|
||||||
if (rewardDestinations.length !== allAccountsInBlock.length) {
|
if (rewardDestinations.length !== allAccountsInBlock.length) {
|
||||||
const payee = (await api.query.staking.payee(
|
const payee = (await api.query.staking.payee(accountAddress)) as unknown as RewardDestination;
|
||||||
accountAddress,
|
|
||||||
)) as unknown as PalletStakingRewardDestination;
|
|
||||||
destinationByAddress[accountAddress] = payee;
|
destinationByAddress[accountAddress] = payee;
|
||||||
rewardDestinationByAddress[blockId] = destinationByAddress;
|
rewardDestinationByAddress[blockId] = destinationByAddress;
|
||||||
return payee;
|
return payee;
|
||||||
@@ -150,7 +138,7 @@ export async function cachedController(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (rewardDestination.isController) {
|
if (rewardDestination.isController) {
|
||||||
controllerNeedAccounts.push(accountId as AccountId);
|
controllerNeedAccounts.push(accountId as unknown as AccountId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +149,6 @@ export async function cachedController(
|
|||||||
return accountId.toString();
|
return accountId.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Commented code doesn't work now, may be fixed later
|
|
||||||
// const bonded = await api.query.staking.bonded.multi(controllerNeedAccounts);
|
|
||||||
const bonded = await api.queryMulti(
|
const bonded = await api.queryMulti(
|
||||||
controllerNeedAccounts.map((account) => [
|
controllerNeedAccounts.map((account) => [
|
||||||
api.query.staking.bonded,
|
api.query.staking.bonded,
|
||||||
@@ -207,7 +193,7 @@ export async function cachedStakingRewardEraIndex(
|
|||||||
api.consts.parachainStaking.rewardPaymentDelay.toHuman();
|
api.consts.parachainStaking.rewardPaymentDelay.toHuman();
|
||||||
// HACK: used to get data from object
|
// HACK: used to get data from object
|
||||||
const eraIndex =
|
const eraIndex =
|
||||||
(era.toJSON() as { current: any }).current - Number(paymentDelay);
|
(era.toJSON() as { current: number }).current - Number(paymentDelay);
|
||||||
|
|
||||||
parachainStakingRewardEra = {};
|
parachainStakingRewardEra = {};
|
||||||
parachainStakingRewardEra[blockId] = eraIndex;
|
parachainStakingRewardEra[blockId] = eraIndex;
|
||||||
@@ -217,22 +203,21 @@ export async function cachedStakingRewardEraIndex(
|
|||||||
|
|
||||||
export async function getPoolMembers(
|
export async function getPoolMembers(
|
||||||
blockId: number,
|
blockId: number,
|
||||||
): Promise<[string, PalletNominationPoolsPoolMember][]> {
|
): Promise<[string, any][]> {
|
||||||
const cachedMembers = poolMembers[blockId];
|
const cachedMembers = poolMembers[blockId];
|
||||||
if (cachedMembers != undefined) {
|
if (cachedMembers != undefined) {
|
||||||
return cachedMembers;
|
return cachedMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
const members: [string, PalletNominationPoolsPoolMember][] = (
|
const members: [string, any][] = (
|
||||||
await api.query.nominationPools.poolMembers.entries()
|
await api.query.nominationPools.poolMembers.entries()
|
||||||
)
|
)
|
||||||
.filter(
|
.filter(
|
||||||
([_, member]) =>
|
([_key, member]) => (member as Option<any>).isSome,
|
||||||
(member as Option<PalletNominationPoolsPoolMember>).isSome,
|
|
||||||
)
|
)
|
||||||
.map(([accountId, member]) => [
|
.map(([accountId, member]) => [
|
||||||
accountId.args[0].toString(),
|
accountId.args[0].toString(),
|
||||||
(member as Option<PalletNominationPoolsPoolMember>).unwrap(),
|
(member as Option<any>).unwrap(),
|
||||||
]);
|
]);
|
||||||
poolMembers = {};
|
poolMembers = {};
|
||||||
poolMembers[blockId] = members;
|
poolMembers[blockId] = members;
|
||||||
|
|||||||
+35
-386
@@ -1,67 +1,22 @@
|
|||||||
import { SubstrateExtrinsic } from "@subql/types";
|
import { SubstrateExtrinsic } from "@subql/types";
|
||||||
import { AssetTransfer, HistoryElement, Transfer, Swap } from "../types";
|
import { HistoryElement, Transfer } from "../types";
|
||||||
import {
|
import {
|
||||||
getAssetIdFromMultilocation,
|
|
||||||
getEventData,
|
|
||||||
callFromProxy,
|
callFromProxy,
|
||||||
callsFromBatch,
|
callsFromBatch,
|
||||||
calculateFeeAsString,
|
calculateFeeAsString,
|
||||||
extrinsicIdFromBlockAndIdx,
|
extrinsicIdFromBlockAndIdx,
|
||||||
eventRecordToSubstrateEvent,
|
|
||||||
isBatch,
|
isBatch,
|
||||||
isProxy,
|
isProxy,
|
||||||
timestamp,
|
|
||||||
isNativeTransfer,
|
isNativeTransfer,
|
||||||
isAssetTransfer,
|
|
||||||
isOrmlTransfer,
|
|
||||||
isSwapExactTokensForTokens,
|
|
||||||
isSwapTokensForExactTokens,
|
|
||||||
isNativeTransferAll,
|
isNativeTransferAll,
|
||||||
isOrmlTransferAll,
|
timestamp,
|
||||||
isEvmTransaction,
|
|
||||||
isEvmExecutedEvent,
|
|
||||||
isAssetTxFeePaidEvent,
|
|
||||||
isEquilibriumTransfer,
|
|
||||||
isHydraOmnipoolBuy,
|
|
||||||
isHydraOmnipoolSell,
|
|
||||||
isHydraRouterSell,
|
|
||||||
isHydraRouterBuy,
|
|
||||||
convertOrmlCurrencyIdToString,
|
|
||||||
} from "./common";
|
} from "./common";
|
||||||
import { CallBase } from "@polkadot/types/types/calls";
|
|
||||||
import { AnyTuple } from "@polkadot/types/types/codec";
|
|
||||||
import { u64 } from "@polkadot/types";
|
|
||||||
import { ethereumEncode } from "@polkadot/util-crypto";
|
|
||||||
import { u128, u32 } from "@polkadot/types-codec";
|
|
||||||
import { convertHydraDxTokenIdToString, findHydraDxFeeTyped } from "./swaps";
|
|
||||||
import { Codec } from "@polkadot/types/types";
|
|
||||||
|
|
||||||
type TransferData = {
|
type TransferData = {
|
||||||
isTransferAll: boolean;
|
isTransferAll: boolean;
|
||||||
transfer: Transfer | AssetTransfer | Swap;
|
transfer: Transfer;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TransferCallback = (
|
|
||||||
isTransferAll: boolean,
|
|
||||||
address: string,
|
|
||||||
amount: any,
|
|
||||||
assetId?: string
|
|
||||||
) => Array<{ isTransferAll: boolean; transfer: Transfer }>;
|
|
||||||
|
|
||||||
type AssetHubSwapCallback = (
|
|
||||||
path: any,
|
|
||||||
amountId: Codec,
|
|
||||||
amountOut: Codec,
|
|
||||||
receiver: Codec
|
|
||||||
) => Array<{ isTransferAll: boolean; transfer: Swap }>;
|
|
||||||
|
|
||||||
type HydraDxSwapCallback = (
|
|
||||||
assetIn: Codec,
|
|
||||||
assetOut: Codec,
|
|
||||||
amountIn: Codec,
|
|
||||||
amountOut: Codec
|
|
||||||
) => { isTransferAll: boolean; transfer: Swap };
|
|
||||||
|
|
||||||
export async function handleHistoryElement(
|
export async function handleHistoryElement(
|
||||||
extrinsic: SubstrateExtrinsic
|
extrinsic: SubstrateExtrinsic
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -74,11 +29,6 @@ export async function handleHistoryElement(
|
|||||||
} else {
|
} else {
|
||||||
await saveExtrinsic(extrinsic);
|
await saveExtrinsic(extrinsic);
|
||||||
}
|
}
|
||||||
} else if (
|
|
||||||
isEvmTransaction(extrinsic.extrinsic.method) &&
|
|
||||||
extrinsic.success
|
|
||||||
) {
|
|
||||||
await saveEvmExtrinsic(extrinsic);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,14 +39,14 @@ function createHistoryElement(
|
|||||||
hash?: string
|
hash?: string
|
||||||
) {
|
) {
|
||||||
let extrinsicHash = hash || extrinsic.extrinsic.hash.toString();
|
let extrinsicHash = hash || extrinsic.extrinsic.hash.toString();
|
||||||
let blockNumber = extrinsic.block.block.header.number.toNumber();
|
let blockNum = extrinsic.block.block.header.number.toNumber();
|
||||||
let extrinsicIdx = extrinsic.idx;
|
let extrinsicIdx = extrinsic.idx;
|
||||||
let extrinsicId = extrinsicIdFromBlockAndIdx(blockNumber, extrinsicIdx);
|
let extrinsicId = extrinsicIdFromBlockAndIdx(blockNum, extrinsicIdx);
|
||||||
let blockTimestamp = timestamp(extrinsic.block);
|
let blockTimestamp = timestamp(extrinsic.block);
|
||||||
|
|
||||||
const historyElement = HistoryElement.create({
|
const historyElement = HistoryElement.create({
|
||||||
id: `${extrinsicId}${suffix}`,
|
id: `${extrinsicId}${suffix}`,
|
||||||
blockNumber,
|
blockNumber: blockNum,
|
||||||
timestamp: blockTimestamp,
|
timestamp: blockTimestamp,
|
||||||
address,
|
address,
|
||||||
});
|
});
|
||||||
@@ -107,35 +57,17 @@ function createHistoryElement(
|
|||||||
return historyElement;
|
return historyElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTransferToHistoryElement(
|
|
||||||
element: HistoryElement,
|
|
||||||
transfer: Transfer | AssetTransfer | Swap
|
|
||||||
) {
|
|
||||||
if ("assetIdIn" in transfer) {
|
|
||||||
element.swap = transfer;
|
|
||||||
} else if ("assetId" in transfer) {
|
|
||||||
element.assetTransfer = transfer;
|
|
||||||
} else {
|
|
||||||
element.transfer = transfer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveFailedTransfers(
|
async function saveFailedTransfers(
|
||||||
transfers: Array<TransferData>,
|
transfers: Array<TransferData>,
|
||||||
extrinsic: SubstrateExtrinsic
|
extrinsic: SubstrateExtrinsic
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const { isTransferAll, transfer } of transfers) {
|
for (const { isTransferAll, transfer } of transfers) {
|
||||||
const isSwap = "assetIdIn" in transfer;
|
const elementFrom = createHistoryElement(extrinsic, transfer.from, `-from`);
|
||||||
const from = isSwap ? transfer.sender : transfer.from;
|
elementFrom.transfer = transfer;
|
||||||
const to = isSwap ? transfer.receiver : transfer.to;
|
|
||||||
const elementFrom = createHistoryElement(extrinsic, from, `-from`);
|
|
||||||
addTransferToHistoryElement(elementFrom, transfer);
|
|
||||||
|
|
||||||
// FIXME: Try to find more appropriate way to handle failed transferAll events
|
|
||||||
if ((!isTransferAll && !isSwap) || from.toString() != to.toString()) {
|
|
||||||
const elementTo = createHistoryElement(extrinsic, to, `-to`);
|
|
||||||
addTransferToHistoryElement(elementTo, transfer);
|
|
||||||
|
|
||||||
|
if (!isTransferAll || transfer.from !== transfer.to) {
|
||||||
|
const elementTo = createHistoryElement(extrinsic, transfer.to, `-to`);
|
||||||
|
elementTo.transfer = transfer;
|
||||||
await elementTo.save();
|
await elementTo.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,35 +92,6 @@ async function saveExtrinsic(extrinsic: SubstrateExtrinsic): Promise<void> {
|
|||||||
await element.save();
|
await element.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveEvmExtrinsic(extrinsic: SubstrateExtrinsic): Promise<void> {
|
|
||||||
const executedEvent = extrinsic.events.find(isEvmExecutedEvent);
|
|
||||||
if (!executedEvent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addressFrom = ethereumEncode(executedEvent.event.data?.[0]?.toString());
|
|
||||||
const hash = executedEvent.event.data?.[2]?.toString();
|
|
||||||
const success = !!(executedEvent.event.data?.[3].toJSON() as any).succeed;
|
|
||||||
|
|
||||||
const element = createHistoryElement(
|
|
||||||
extrinsic,
|
|
||||||
addressFrom,
|
|
||||||
"-extrinsic",
|
|
||||||
hash
|
|
||||||
);
|
|
||||||
|
|
||||||
element.extrinsic = {
|
|
||||||
hash,
|
|
||||||
module: extrinsic.extrinsic.method.section,
|
|
||||||
call: extrinsic.extrinsic.method.method,
|
|
||||||
success,
|
|
||||||
fee: calculateFeeAsString(extrinsic, addressFrom),
|
|
||||||
};
|
|
||||||
|
|
||||||
await element.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Success Transfer emits Transfer event that is handled at Transfers.ts handleTransfer()
|
|
||||||
function findFailedTransferCalls(
|
function findFailedTransferCalls(
|
||||||
extrinsic: SubstrateExtrinsic
|
extrinsic: SubstrateExtrinsic
|
||||||
): Array<TransferData> | null {
|
): Array<TransferData> | null {
|
||||||
@@ -197,121 +100,30 @@ function findFailedTransferCalls(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let sender = extrinsic.extrinsic.signer;
|
let sender = extrinsic.extrinsic.signer;
|
||||||
const transferCallback: TransferCallback = (
|
|
||||||
isTransferAll,
|
|
||||||
address,
|
|
||||||
amount,
|
|
||||||
assetId?
|
|
||||||
) => {
|
|
||||||
const transfer: Transfer = {
|
|
||||||
amount: amount.toString(),
|
|
||||||
from: sender.toString(),
|
|
||||||
to: address,
|
|
||||||
fee: calculateFeeAsString(extrinsic),
|
|
||||||
eventIdx: -1,
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (assetId) {
|
|
||||||
(transfer as AssetTransfer).assetId = assetId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
isTransferAll,
|
|
||||||
transfer,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const assetHubSwapCallback: AssetHubSwapCallback = (
|
|
||||||
path,
|
|
||||||
amountIn,
|
|
||||||
amountOut,
|
|
||||||
receiver
|
|
||||||
) => {
|
|
||||||
let assetIdFee = "native";
|
|
||||||
let fee = calculateFeeAsString(extrinsic);
|
|
||||||
let foundAssetTxFeePaid = extrinsic.block.events.find((e) =>
|
|
||||||
isAssetTxFeePaidEvent(eventRecordToSubstrateEvent(e))
|
|
||||||
);
|
|
||||||
if (foundAssetTxFeePaid !== undefined) {
|
|
||||||
const [who, actual_fee, tip, rawAssetIdFee] = getEventData(
|
|
||||||
eventRecordToSubstrateEvent(foundAssetTxFeePaid)
|
|
||||||
);
|
|
||||||
if ("interior" in rawAssetIdFee) {
|
|
||||||
assetIdFee = getAssetIdFromMultilocation(rawAssetIdFee);
|
|
||||||
fee = actual_fee.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const assetIdIn = getAssetIdFromMultilocation(path[0], true);
|
|
||||||
const assetIdOut = getAssetIdFromMultilocation(
|
|
||||||
path[path["length"] - 1],
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
if (assetIdIn === undefined || assetIdOut === undefined) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const swap: Swap = {
|
|
||||||
assetIdIn: assetIdIn,
|
|
||||||
amountIn: amountIn.toString(),
|
|
||||||
assetIdOut: assetIdOut,
|
|
||||||
amountOut: amountOut.toString(),
|
|
||||||
sender: sender.toString(),
|
|
||||||
receiver: receiver.toString(),
|
|
||||||
assetIdFee: assetIdFee,
|
|
||||||
fee: fee,
|
|
||||||
eventIdx: -1,
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
isTransferAll: false,
|
|
||||||
transfer: swap,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const hydraDxSwapCallback: HydraDxSwapCallback = (
|
|
||||||
assetIn: Codec,
|
|
||||||
assetOut: Codec,
|
|
||||||
amountIn: Codec,
|
|
||||||
amountOut: Codec
|
|
||||||
) => {
|
|
||||||
let fee = findHydraDxFeeTyped(extrinsic.events);
|
|
||||||
|
|
||||||
const assetIdIn = convertHydraDxTokenIdToString(assetIn);
|
|
||||||
const assetIdOut = convertHydraDxTokenIdToString(assetOut);
|
|
||||||
|
|
||||||
const swap: Swap = {
|
|
||||||
assetIdIn: assetIdIn,
|
|
||||||
amountIn: amountIn.toString(),
|
|
||||||
assetIdOut: assetIdOut,
|
|
||||||
amountOut: amountOut.toString(),
|
|
||||||
sender: sender.toString(),
|
|
||||||
receiver: sender.toString(),
|
|
||||||
assetIdFee: fee.tokenId,
|
|
||||||
fee: fee.amount,
|
|
||||||
eventIdx: -1,
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const createTransfer = (
|
||||||
|
isTransferAll: boolean,
|
||||||
|
address: string,
|
||||||
|
amount: bigint
|
||||||
|
): TransferData => {
|
||||||
return {
|
return {
|
||||||
isTransferAll: false,
|
isTransferAll,
|
||||||
transfer: swap,
|
transfer: {
|
||||||
|
amount: amount.toString(),
|
||||||
|
from: sender.toString(),
|
||||||
|
to: address,
|
||||||
|
fee: calculateFeeAsString(extrinsic),
|
||||||
|
eventIdx: -1,
|
||||||
|
success: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let transferCalls = determineTransferCallsArgs(
|
let transferCalls = determineTransferCallsArgs(
|
||||||
extrinsic.extrinsic.method,
|
extrinsic.extrinsic.method,
|
||||||
transferCallback,
|
createTransfer
|
||||||
assetHubSwapCallback,
|
|
||||||
hydraDxSwapCallback
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (transferCalls.length == 0) {
|
if (transferCalls.length == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -320,186 +132,23 @@ function findFailedTransferCalls(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function determineTransferCallsArgs(
|
function determineTransferCallsArgs(
|
||||||
causeCall: CallBase<AnyTuple>,
|
causeCall: any,
|
||||||
transferCallback: TransferCallback,
|
createTransfer: (isTransferAll: boolean, address: string, amount: bigint) => TransferData
|
||||||
assetHubSwapCallback: AssetHubSwapCallback,
|
|
||||||
hydraDxSwapCallback: HydraDxSwapCallback
|
|
||||||
): Array<TransferData> {
|
): Array<TransferData> {
|
||||||
if (isNativeTransfer(causeCall)) {
|
if (isNativeTransfer(causeCall)) {
|
||||||
return transferCallback(false, ...extractArgsFromTransfer(causeCall));
|
const [destinationAddress, amount] = causeCall.args;
|
||||||
} else if (isAssetTransfer(causeCall)) {
|
return [createTransfer(false, destinationAddress.toString(), (amount as any).toBigInt())];
|
||||||
return transferCallback(false, ...extractArgsFromAssetTransfer(causeCall));
|
|
||||||
} else if (isOrmlTransfer(causeCall)) {
|
|
||||||
return transferCallback(false, ...extractArgsFromOrmlTransfer(causeCall));
|
|
||||||
} else if (isEquilibriumTransfer(causeCall)) {
|
|
||||||
return transferCallback(
|
|
||||||
false,
|
|
||||||
...extractArgsFromEquilibriumTransfer(causeCall)
|
|
||||||
);
|
|
||||||
} else if (isNativeTransferAll(causeCall)) {
|
} else if (isNativeTransferAll(causeCall)) {
|
||||||
return transferCallback(true, ...extractArgsFromTransferAll(causeCall));
|
const [destinationAddress] = causeCall.args;
|
||||||
} else if (isOrmlTransferAll(causeCall)) {
|
return [createTransfer(true, destinationAddress.toString(), BigInt(0))];
|
||||||
return transferCallback(true, ...extractArgsFromOrmlTransferAll(causeCall));
|
|
||||||
} else if (isSwapExactTokensForTokens(causeCall)) {
|
|
||||||
return assetHubSwapCallback(
|
|
||||||
...extractArgsFromSwapExactTokensForTokens(causeCall)
|
|
||||||
);
|
|
||||||
} else if (isSwapTokensForExactTokens(causeCall)) {
|
|
||||||
return assetHubSwapCallback(
|
|
||||||
...extractArgsFromSwapTokensForExactTokens(causeCall)
|
|
||||||
);
|
|
||||||
} else if (isHydraOmnipoolBuy(causeCall)) {
|
|
||||||
return [hydraDxSwapCallback(...extractArgsFromHydraOmnipoolBuy(causeCall))];
|
|
||||||
} else if (isHydraOmnipoolSell(causeCall)) {
|
|
||||||
return [
|
|
||||||
hydraDxSwapCallback(...extractArgsFromHydraOmnipoolSell(causeCall)),
|
|
||||||
];
|
|
||||||
} else if (isHydraRouterBuy(causeCall)) {
|
|
||||||
return [hydraDxSwapCallback(...extractArgsFromHydraRouterBuy(causeCall))];
|
|
||||||
} else if (isHydraRouterSell(causeCall)) {
|
|
||||||
return [hydraDxSwapCallback(...extractArgsFromHydraRouterSell(causeCall))];
|
|
||||||
} else if (isBatch(causeCall)) {
|
} else if (isBatch(causeCall)) {
|
||||||
return callsFromBatch(causeCall)
|
return callsFromBatch(causeCall)
|
||||||
.map((call) => {
|
.map((call: any) => determineTransferCallsArgs(call, createTransfer))
|
||||||
return determineTransferCallsArgs(
|
|
||||||
call,
|
|
||||||
transferCallback,
|
|
||||||
assetHubSwapCallback,
|
|
||||||
hydraDxSwapCallback
|
|
||||||
).map((value, index, array) => {
|
|
||||||
return value;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.flat();
|
.flat();
|
||||||
} else if (isProxy(causeCall)) {
|
} else if (isProxy(causeCall)) {
|
||||||
let proxyCall = callFromProxy(causeCall);
|
let proxyCall = callFromProxy(causeCall);
|
||||||
return determineTransferCallsArgs(
|
return determineTransferCallsArgs(proxyCall, createTransfer);
|
||||||
proxyCall,
|
|
||||||
transferCallback,
|
|
||||||
assetHubSwapCallback,
|
|
||||||
hydraDxSwapCallback
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractArgsFromTransfer(call: CallBase<AnyTuple>): [string, bigint] {
|
|
||||||
const [destinationAddress, amount] = call.args;
|
|
||||||
|
|
||||||
return [destinationAddress.toString(), (amount as u64).toBigInt()];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromAssetTransfer(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [string, bigint, string] {
|
|
||||||
const [assetId, destinationAddress, amount] = call.args;
|
|
||||||
|
|
||||||
return [
|
|
||||||
destinationAddress.toString(),
|
|
||||||
(amount as u64).toBigInt(),
|
|
||||||
assetId.toString(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromOrmlTransfer(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [string, bigint, string] {
|
|
||||||
const [destinationAddress, currencyId, amount] = call.args;
|
|
||||||
|
|
||||||
return [
|
|
||||||
destinationAddress.toString(),
|
|
||||||
(amount as u64).toBigInt(),
|
|
||||||
currencyId.toHex().toString(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromEquilibriumTransfer(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [string, bigint, string] {
|
|
||||||
const [assetId, destinationAddress, amount] = call.args;
|
|
||||||
|
|
||||||
return [
|
|
||||||
destinationAddress.toString(),
|
|
||||||
(amount as u64).toBigInt(),
|
|
||||||
assetId.toString(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromTransferAll(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [string, bigint] {
|
|
||||||
const [destinationAddress] = call.args;
|
|
||||||
|
|
||||||
return [destinationAddress.toString(), BigInt(0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromOrmlTransferAll(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [string, bigint, string] {
|
|
||||||
const [destinationAddress, currencyId] = call.args;
|
|
||||||
|
|
||||||
return [
|
|
||||||
destinationAddress.toString(),
|
|
||||||
BigInt(0),
|
|
||||||
convertOrmlCurrencyIdToString(currencyId),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromSwapExactTokensForTokens(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [any, Codec, Codec, Codec] {
|
|
||||||
const [path, amountIn, amountOut, receiver, _] = call.args;
|
|
||||||
|
|
||||||
return [path, amountIn, amountOut, receiver];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromSwapTokensForExactTokens(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [any, Codec, Codec, Codec] {
|
|
||||||
const [path, amountOut, amountIn, receiver, _] = call.args;
|
|
||||||
|
|
||||||
return [path, amountIn, amountOut, receiver];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromHydraRouterSell(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [Codec, Codec, Codec, Codec] {
|
|
||||||
const [assetIn, assetOut, amountIn, minAmountOut, _] = call.args;
|
|
||||||
|
|
||||||
return [assetIn, assetOut, amountIn, minAmountOut];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromHydraRouterBuy(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [Codec, Codec, Codec, Codec] {
|
|
||||||
const [assetIn, assetOut, amountOut, maxAmountIn, _] = call.args;
|
|
||||||
|
|
||||||
return [assetIn, assetOut, maxAmountIn, amountOut];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromHydraOmnipoolSell(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [Codec, Codec, Codec, Codec] {
|
|
||||||
const [assetIn, assetOut, amount, minBuyAmount, _] = call.args;
|
|
||||||
|
|
||||||
return [
|
|
||||||
assetIn,
|
|
||||||
assetOut,
|
|
||||||
amount, // amountIn
|
|
||||||
minBuyAmount, // amountOut
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractArgsFromHydraOmnipoolBuy(
|
|
||||||
call: CallBase<AnyTuple>
|
|
||||||
): [Codec, Codec, Codec, Codec] {
|
|
||||||
const [assetOut, assetIn, amount, maxSellAmount, _] = call.args;
|
|
||||||
|
|
||||||
return [
|
|
||||||
assetIn,
|
|
||||||
assetOut,
|
|
||||||
maxSellAmount, // amountIn
|
|
||||||
amount, // amountOut
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|||||||
+9
-18
@@ -2,13 +2,8 @@ import { SubstrateEvent } from "@subql/types";
|
|||||||
import { eventId } from "./common";
|
import { eventId } from "./common";
|
||||||
import { EraValidatorInfo } from "../types/models/EraValidatorInfo";
|
import { EraValidatorInfo } from "../types/models/EraValidatorInfo";
|
||||||
import { IndividualExposure } from "../types";
|
import { IndividualExposure } from "../types";
|
||||||
import {
|
import { Option } from "@pezkuwi/types";
|
||||||
SpStakingPagedExposureMetadata,
|
import { Exposure } from "@pezkuwi/types/interfaces/staking";
|
||||||
SpStakingExposurePage,
|
|
||||||
} from "@polkadot/types/lookup";
|
|
||||||
import { Option } from "@polkadot/types";
|
|
||||||
import { INumber } from "@polkadot/types-codec/types/interfaces";
|
|
||||||
import { Exposure } from "@polkadot/types/interfaces";
|
|
||||||
|
|
||||||
export async function handleStakersElected(
|
export async function handleStakersElected(
|
||||||
event: SubstrateEvent,
|
event: SubstrateEvent,
|
||||||
@@ -17,7 +12,7 @@ export async function handleStakersElected(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function handleNewEra(event: SubstrateEvent): Promise<void> {
|
export async function handleNewEra(event: SubstrateEvent): Promise<void> {
|
||||||
const currentEra = ((await api.query.staking.currentEra()) as Option<INumber>)
|
const currentEra = ((await api.query.staking.currentEra()) as Option<any>)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.toNumber();
|
.toNumber();
|
||||||
|
|
||||||
@@ -65,19 +60,17 @@ async function processEraStakersPaged(
|
|||||||
const pages = await api.query.staking.erasStakersPaged.entries(currentEra);
|
const pages = await api.query.staking.erasStakersPaged.entries(currentEra);
|
||||||
|
|
||||||
interface AccumulatorType {
|
interface AccumulatorType {
|
||||||
[key: string]: any;
|
[key: string]: { [page: number]: IndividualExposure[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
const othersCounted = pages.reduce(
|
const othersCounted = pages.reduce(
|
||||||
(accumulator: AccumulatorType, [key, exp]) => {
|
(accumulator: AccumulatorType, [key, exp]) => {
|
||||||
const exposure = (
|
const exposure = (exp as Option<any>).unwrap();
|
||||||
exp as unknown as Option<SpStakingExposurePage>
|
|
||||||
).unwrap();
|
|
||||||
const [, validatorId, pageId] = key.args;
|
const [, validatorId, pageId] = key.args;
|
||||||
const pageNumber = (pageId as INumber).toNumber();
|
const pageNumber = (pageId as any).toNumber();
|
||||||
const validatorIdString = validatorId.toString();
|
const validatorIdString = validatorId.toString();
|
||||||
|
|
||||||
const others = exposure.others.map(({ who, value }) => {
|
const others: IndividualExposure[] = exposure.others.map(({ who, value }: any) => {
|
||||||
return {
|
return {
|
||||||
who: who.toString(),
|
who: who.toString(),
|
||||||
value: value.toString(),
|
value: value.toString(),
|
||||||
@@ -93,13 +86,11 @@ async function processEraStakersPaged(
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (const [key, exp] of overview) {
|
for (const [key, exp] of overview) {
|
||||||
const exposure = (
|
const exposure = (exp as Option<any>).unwrap();
|
||||||
exp as unknown as Option<SpStakingPagedExposureMetadata>
|
|
||||||
).unwrap();
|
|
||||||
const [, validatorId] = key.args;
|
const [, validatorId] = key.args;
|
||||||
let validatorIdString = validatorId.toString();
|
let validatorIdString = validatorId.toString();
|
||||||
|
|
||||||
let others = [];
|
let others: IndividualExposure[] = [];
|
||||||
for (let i = 0; i < exposure.pageCount.toNumber(); ++i) {
|
for (let i = 0; i < exposure.pageCount.toNumber(); ++i) {
|
||||||
others.push(...othersCounted[validatorIdString][i]);
|
others.push(...othersCounted[validatorIdString][i]);
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-40
@@ -12,25 +12,15 @@ import {
|
|||||||
eventIdWithAddress,
|
eventIdWithAddress,
|
||||||
blockNumber,
|
blockNumber,
|
||||||
} from "./common";
|
} from "./common";
|
||||||
import { Codec } from "@polkadot/types/types";
|
|
||||||
import { u32 } from "@polkadot/types-codec";
|
|
||||||
import { INumber } from "@polkadot/types-codec/types/interfaces";
|
|
||||||
import {
|
|
||||||
PalletNominationPoolsBondedPoolInner,
|
|
||||||
PalletNominationPoolsPoolMember,
|
|
||||||
PalletNominationPoolsSubPools,
|
|
||||||
} from "@polkadot/types/lookup";
|
|
||||||
import {
|
import {
|
||||||
handleGenericForTxHistory,
|
handleGenericForTxHistory,
|
||||||
updateAccumulatedGenericReward,
|
updateAccumulatedGenericReward,
|
||||||
} from "./Rewards";
|
} from "./Rewards";
|
||||||
import { getPoolMembers } from "./Cache";
|
import { getPoolMembers } from "./Cache";
|
||||||
import { Option } from "@polkadot/types";
|
import { Option } from "@pezkuwi/types";
|
||||||
|
|
||||||
export async function handlePoolReward(
|
export async function handlePoolReward(
|
||||||
rewardEvent: SubstrateEvent<
|
rewardEvent: SubstrateEvent,
|
||||||
[accountId: Codec, poolId: INumber, reward: INumber]
|
|
||||||
>,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await handlePoolRewardForTxHistory(rewardEvent);
|
await handlePoolRewardForTxHistory(rewardEvent);
|
||||||
let accumulatedReward = await updateAccumulatedPoolReward(rewardEvent, true);
|
let accumulatedReward = await updateAccumulatedPoolReward(rewardEvent, true);
|
||||||
@@ -42,17 +32,15 @@ export async function handlePoolReward(
|
|||||||
await updateAccountPoolRewards(
|
await updateAccountPoolRewards(
|
||||||
rewardEvent,
|
rewardEvent,
|
||||||
accountId.toString(),
|
accountId.toString(),
|
||||||
amount.toBigInt(),
|
(amount as any).toBigInt(),
|
||||||
poolId.toNumber(),
|
(poolId as any).toNumber(),
|
||||||
RewardType.reward,
|
RewardType.reward,
|
||||||
accumulatedReward.amount,
|
accumulatedReward.amount,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handlePoolRewardForTxHistory(
|
async function handlePoolRewardForTxHistory(
|
||||||
rewardEvent: SubstrateEvent<
|
rewardEvent: SubstrateEvent,
|
||||||
[accountId: Codec, poolId: INumber, reward: INumber]
|
|
||||||
>,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {
|
const {
|
||||||
event: {
|
event: {
|
||||||
@@ -67,7 +55,7 @@ async function handlePoolRewardForTxHistory(
|
|||||||
eventIdx: rewardEvent.idx,
|
eventIdx: rewardEvent.idx,
|
||||||
amount: amount.toString(),
|
amount: amount.toString(),
|
||||||
isReward: true,
|
isReward: true,
|
||||||
poolId: poolId.toNumber(),
|
poolId: (poolId as any).toNumber(),
|
||||||
};
|
};
|
||||||
return element;
|
return element;
|
||||||
},
|
},
|
||||||
@@ -75,7 +63,7 @@ async function handlePoolRewardForTxHistory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateAccumulatedPoolReward(
|
async function updateAccumulatedPoolReward(
|
||||||
event: SubstrateEvent<[accountId: Codec, poolId: INumber, reward: INumber]>,
|
event: SubstrateEvent,
|
||||||
isReward: boolean,
|
isReward: boolean,
|
||||||
): Promise<AccumulatedReward> {
|
): Promise<AccumulatedReward> {
|
||||||
let {
|
let {
|
||||||
@@ -86,7 +74,7 @@ async function updateAccumulatedPoolReward(
|
|||||||
return await updateAccumulatedGenericReward(
|
return await updateAccumulatedGenericReward(
|
||||||
AccumulatedPoolReward,
|
AccumulatedPoolReward,
|
||||||
accountId.toString(),
|
accountId.toString(),
|
||||||
amount.toBigInt(),
|
(amount as any).toBigInt(),
|
||||||
isReward,
|
isReward,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -114,62 +102,60 @@ async function updateAccountPoolRewards(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function handlePoolBondedSlash(
|
export async function handlePoolBondedSlash(
|
||||||
bondedSlashEvent: SubstrateEvent<[poolId: INumber, slash: INumber]>,
|
bondedSlashEvent: SubstrateEvent,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {
|
const {
|
||||||
event: {
|
event: {
|
||||||
data: [poolIdEncoded, slash],
|
data: [poolIdEncoded, slash],
|
||||||
},
|
},
|
||||||
} = bondedSlashEvent;
|
} = bondedSlashEvent;
|
||||||
const poolId = poolIdEncoded.toNumber();
|
const poolId = (poolIdEncoded as any).toNumber();
|
||||||
|
|
||||||
const poolOption = (await api.query.nominationPools.bondedPools(
|
const poolOption = (await api.query.nominationPools.bondedPools(
|
||||||
poolId,
|
poolId,
|
||||||
)) as Option<PalletNominationPoolsBondedPoolInner>;
|
)) as Option<any>;
|
||||||
const pool = poolOption.unwrap();
|
const pool = poolOption.unwrap();
|
||||||
|
|
||||||
await handleRelaychainPooledStakingSlash(
|
await handleRelaychainPooledStakingSlash(
|
||||||
bondedSlashEvent,
|
bondedSlashEvent,
|
||||||
poolId,
|
poolId,
|
||||||
pool.points.toBigInt(),
|
pool.points.toBigInt(),
|
||||||
slash.toBigInt(),
|
(slash as any).toBigInt(),
|
||||||
(member: PalletNominationPoolsPoolMember): bigint => {
|
(member: any): bigint => {
|
||||||
return member.points.toBigInt();
|
return member.points.toBigInt();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handlePoolUnbondingSlash(
|
export async function handlePoolUnbondingSlash(
|
||||||
unbondingSlashEvent: SubstrateEvent<
|
unbondingSlashEvent: SubstrateEvent,
|
||||||
[poolId: INumber, era: INumber, slash: INumber]
|
|
||||||
>,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {
|
const {
|
||||||
event: {
|
event: {
|
||||||
data: [poolId, era, slash],
|
data: [poolId, era, slash],
|
||||||
},
|
},
|
||||||
} = unbondingSlashEvent;
|
} = unbondingSlashEvent;
|
||||||
const poolIdNumber = poolId.toNumber();
|
const poolIdNumber = (poolId as any).toNumber();
|
||||||
const eraIdNumber = era.toNumber();
|
const eraIdNumber = (era as any).toNumber();
|
||||||
|
|
||||||
const unbondingPools = (
|
const unbondingPools = (
|
||||||
(await api.query.nominationPools.subPoolsStorage(
|
(await api.query.nominationPools.subPoolsStorage(
|
||||||
poolIdNumber,
|
poolIdNumber,
|
||||||
)) as Option<PalletNominationPoolsSubPools>
|
)) as Option<any>
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
const pool =
|
const pool =
|
||||||
unbondingPools.withEra.get(eraIdNumber as unknown as u32) ??
|
(unbondingPools.withEra as any).get(eraIdNumber) ??
|
||||||
unbondingPools.noEra;
|
unbondingPools.noEra;
|
||||||
|
|
||||||
await handleRelaychainPooledStakingSlash(
|
await handleRelaychainPooledStakingSlash(
|
||||||
unbondingSlashEvent,
|
unbondingSlashEvent,
|
||||||
poolIdNumber,
|
poolIdNumber,
|
||||||
pool.points.toBigInt(),
|
pool.points.toBigInt(),
|
||||||
slash.toBigInt(),
|
(slash as any).toBigInt(),
|
||||||
(member: PalletNominationPoolsPoolMember): bigint => {
|
(member: any): bigint => {
|
||||||
return (
|
return (
|
||||||
member.unbondingEras.get(eraIdNumber as unknown as u32)?.toBigInt() ??
|
((member.unbondingEras as any).get(eraIdNumber))?.toBigInt() ??
|
||||||
BigInt(0)
|
BigInt(0)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -181,7 +167,7 @@ async function handleRelaychainPooledStakingSlash(
|
|||||||
poolId: number,
|
poolId: number,
|
||||||
poolPoints: bigint,
|
poolPoints: bigint,
|
||||||
slash: bigint,
|
slash: bigint,
|
||||||
memberPointsCounter: (member: PalletNominationPoolsPoolMember) => bigint,
|
memberPointsCounter: (member: any) => bigint,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (poolPoints == BigInt(0)) {
|
if (poolPoints == BigInt(0)) {
|
||||||
return;
|
return;
|
||||||
@@ -229,16 +215,16 @@ async function handlePoolSlashForTxHistory(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const extrinsic = slashEvent.extrinsic;
|
const extrinsic = slashEvent.extrinsic;
|
||||||
const block = slashEvent.block;
|
const block = slashEvent.block;
|
||||||
const blockNumber = block.block.header.number.toString();
|
const blockNum = block.block.header.number.toString();
|
||||||
const blockTimestamp = timestamp(block);
|
const blockTimestamp = timestamp(block);
|
||||||
const eventId = eventIdFromBlockAndIdxAndAddress(
|
const evtId = eventIdFromBlockAndIdxAndAddress(
|
||||||
blockNumber,
|
blockNum,
|
||||||
slashEvent.idx.toString(),
|
slashEvent.idx.toString(),
|
||||||
accountId,
|
accountId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const element = HistoryElement.create({
|
const element = HistoryElement.create({
|
||||||
id: eventId,
|
id: evtId,
|
||||||
timestamp: blockTimestamp,
|
timestamp: blockTimestamp,
|
||||||
blockNumber: block.block.header.number.toNumber(),
|
blockNumber: block.block.header.number.toNumber(),
|
||||||
extrinsicHash:
|
extrinsicHash:
|
||||||
|
|||||||
+28
-123
@@ -21,64 +21,50 @@ import {
|
|||||||
callFromProxy,
|
callFromProxy,
|
||||||
blockNumber,
|
blockNumber,
|
||||||
} from "./common";
|
} from "./common";
|
||||||
import { CallBase } from "@polkadot/types/types/calls";
|
|
||||||
import { AnyTuple } from "@polkadot/types/types/codec";
|
|
||||||
import { EraIndex } from "@polkadot/types/interfaces/staking";
|
|
||||||
import { Balance, EventRecord } from "@polkadot/types/interfaces";
|
|
||||||
import {
|
import {
|
||||||
cachedRewardDestination,
|
cachedRewardDestination,
|
||||||
cachedController,
|
cachedController,
|
||||||
cachedStakingRewardEraIndex,
|
cachedStakingRewardEraIndex,
|
||||||
} from "./Cache";
|
} from "./Cache";
|
||||||
import { Codec } from "@polkadot/types/types";
|
|
||||||
import { INumber } from "@polkadot/types-codec/types/interfaces";
|
|
||||||
|
|
||||||
function isPayoutStakers(call: CallBase<AnyTuple>): boolean {
|
function isPayoutStakers(call: any): boolean {
|
||||||
return call.method == "payoutStakers";
|
return call.method == "payoutStakers";
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPayoutStakersByPage(call: CallBase<AnyTuple>): boolean {
|
function isPayoutStakersByPage(call: any): boolean {
|
||||||
return call.method == "payoutStakersByPage";
|
return call.method == "payoutStakersByPage";
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPayoutValidator(call: CallBase<AnyTuple>): boolean {
|
function isPayoutValidator(call: any): boolean {
|
||||||
return call.method == "payoutValidator";
|
return call.method == "payoutValidator";
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractArgsFromPayoutStakers(
|
function extractArgsFromPayoutStakers(call: any): [string, number] {
|
||||||
call: CallBase<AnyTuple>,
|
|
||||||
): [string, number] {
|
|
||||||
const [validatorAddressRaw, eraRaw] = call.args;
|
const [validatorAddressRaw, eraRaw] = call.args;
|
||||||
|
|
||||||
return [validatorAddressRaw.toString(), (eraRaw as EraIndex).toNumber()];
|
return [validatorAddressRaw.toString(), (eraRaw as any).toNumber()];
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractArgsFromPayoutStakersByPage(
|
function extractArgsFromPayoutStakersByPage(call: any): [string, number] {
|
||||||
call: CallBase<AnyTuple>,
|
|
||||||
): [string, number] {
|
|
||||||
const [validatorAddressRaw, eraRaw, _] = call.args;
|
const [validatorAddressRaw, eraRaw, _] = call.args;
|
||||||
|
|
||||||
return [validatorAddressRaw.toString(), (eraRaw as EraIndex).toNumber()];
|
return [validatorAddressRaw.toString(), (eraRaw as any).toNumber()];
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractArgsFromPayoutValidator(
|
function extractArgsFromPayoutValidator(
|
||||||
call: CallBase<AnyTuple>,
|
call: any,
|
||||||
sender: string,
|
sender: string,
|
||||||
): [string, number] {
|
): [string, number] {
|
||||||
const [eraRaw] = call.args;
|
const [eraRaw] = call.args;
|
||||||
|
|
||||||
return [sender, (eraRaw as EraIndex).toNumber()];
|
return [sender, (eraRaw as any).toNumber()];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleRewarded(
|
export async function handleRewarded(rewardEvent: SubstrateEvent): Promise<void> {
|
||||||
rewardEvent: SubstrateEvent<[accountId: Codec, reward: INumber]>,
|
|
||||||
): Promise<void> {
|
|
||||||
await handleReward(rewardEvent);
|
await handleReward(rewardEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleReward(
|
export async function handleReward(rewardEvent: SubstrateEvent): Promise<void> {
|
||||||
rewardEvent: SubstrateEvent<[accountId: Codec, reward: INumber]>,
|
|
||||||
): Promise<void> {
|
|
||||||
await handleRewardForTxHistory(rewardEvent);
|
await handleRewardForTxHistory(rewardEvent);
|
||||||
let accumulatedReward = await updateAccumulatedReward(rewardEvent, true);
|
let accumulatedReward = await updateAccumulatedReward(rewardEvent, true);
|
||||||
await updateAccountRewards(
|
await updateAccountRewards(
|
||||||
@@ -86,22 +72,6 @@ export async function handleReward(
|
|||||||
RewardType.reward,
|
RewardType.reward,
|
||||||
accumulatedReward.amount,
|
accumulatedReward.amount,
|
||||||
);
|
);
|
||||||
// let rewardEventId = eventId(rewardEvent)
|
|
||||||
// try {
|
|
||||||
// let errorOccursOnEvent = await ErrorEvent.get(rewardEventId)
|
|
||||||
// if (errorOccursOnEvent !== undefined) {
|
|
||||||
// logger.info(`Skip rewardEvent: ${rewardEventId}`)
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// await handleRewardForTxHistory(rewardEvent)
|
|
||||||
// await updateAccumulatedReward(rewardEvent, true)
|
|
||||||
// } catch (error) {
|
|
||||||
// logger.error(`Got error on reward event: ${rewardEventId}: ${error.toString()}`)
|
|
||||||
// let saveError = new ErrorEvent(rewardEventId)
|
|
||||||
// saveError.description = error.toString()
|
|
||||||
// await saveError.save()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleRewardForTxHistory(
|
async function handleRewardForTxHistory(
|
||||||
@@ -209,7 +179,7 @@ async function handleRewardForTxHistory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function determinePayoutCallsArgs(
|
function determinePayoutCallsArgs(
|
||||||
causeCall: CallBase<AnyTuple>,
|
causeCall: any,
|
||||||
sender: string,
|
sender: string,
|
||||||
): [string, number][] {
|
): [string, number][] {
|
||||||
if (isPayoutStakers(causeCall)) {
|
if (isPayoutStakers(causeCall)) {
|
||||||
@@ -220,7 +190,7 @@ function determinePayoutCallsArgs(
|
|||||||
return [extractArgsFromPayoutValidator(causeCall, sender)];
|
return [extractArgsFromPayoutValidator(causeCall, sender)];
|
||||||
} else if (isBatch(causeCall)) {
|
} else if (isBatch(causeCall)) {
|
||||||
return callsFromBatch(causeCall)
|
return callsFromBatch(causeCall)
|
||||||
.map((call) => {
|
.map((call: any) => {
|
||||||
return determinePayoutCallsArgs(call, sender).map(
|
return determinePayoutCallsArgs(call, sender).map(
|
||||||
(value, index, array) => {
|
(value, index, array) => {
|
||||||
return value;
|
return value;
|
||||||
@@ -236,15 +206,11 @@ function determinePayoutCallsArgs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleSlashed(
|
export async function handleSlashed(slashEvent: SubstrateEvent): Promise<void> {
|
||||||
slashEvent: SubstrateEvent<[accountId: Codec, slash: INumber]>,
|
|
||||||
): Promise<void> {
|
|
||||||
await handleSlash(slashEvent);
|
await handleSlash(slashEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleSlash(
|
export async function handleSlash(slashEvent: SubstrateEvent): Promise<void> {
|
||||||
slashEvent: SubstrateEvent<[accountId: Codec, slash: INumber]>,
|
|
||||||
): Promise<void> {
|
|
||||||
await handleSlashForTxHistory(slashEvent);
|
await handleSlashForTxHistory(slashEvent);
|
||||||
let accumulatedReward = await updateAccumulatedReward(slashEvent, false);
|
let accumulatedReward = await updateAccumulatedReward(slashEvent, false);
|
||||||
await updateAccountRewards(
|
await updateAccountRewards(
|
||||||
@@ -252,29 +218,13 @@ export async function handleSlash(
|
|||||||
RewardType.slash,
|
RewardType.slash,
|
||||||
accumulatedReward.amount,
|
accumulatedReward.amount,
|
||||||
);
|
);
|
||||||
// let slashEventId = eventId(slashEvent)
|
|
||||||
// try {
|
|
||||||
// let errorOccursOnEvent = await ErrorEvent.get(slashEventId)
|
|
||||||
// if (errorOccursOnEvent !== undefined) {
|
|
||||||
// logger.info(`Skip slashEvent: ${slashEventId}`)
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// await handleSlashForTxHistory(slashEvent)
|
|
||||||
// await updateAccumulatedReward(slashEvent, false)
|
|
||||||
// } catch (error) {
|
|
||||||
// logger.error(`Got error on slash event: ${slashEventId}: ${error.toString()}`)
|
|
||||||
// let saveError = new ErrorEvent(slashEventId)
|
|
||||||
// saveError.description = error.toString()
|
|
||||||
// await saveError.save()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getValidators(era: number): Promise<Set<string>> {
|
async function getValidators(era: number): Promise<Set<string>> {
|
||||||
const eraStakersInSlashEra = await (api.query.staking.erasStakersClipped
|
const eraStakersInSlashEra = await (api.query.staking.erasStakersClipped
|
||||||
? api.query.staking.erasStakersClipped.keys(era)
|
? api.query.staking.erasStakersClipped.keys(era)
|
||||||
: api.query.staking.erasStakersOverview.keys(era));
|
: api.query.staking.erasStakersOverview.keys(era));
|
||||||
const validatorsInSlashEra = eraStakersInSlashEra.map((key) => {
|
const validatorsInSlashEra = eraStakersInSlashEra.map((key: any) => {
|
||||||
let [, validatorId] = key.args;
|
let [, validatorId] = key.args;
|
||||||
|
|
||||||
return validatorId.toString();
|
return validatorId.toString();
|
||||||
@@ -347,7 +297,7 @@ async function buildRewardEvents<A>(
|
|||||||
amount: string,
|
amount: string,
|
||||||
) => Reward,
|
) => Reward,
|
||||||
) {
|
) {
|
||||||
let blockNumber = block.block.header.number.toString();
|
let blockNum = block.block.header.number.toString();
|
||||||
let blockTimestamp = timestamp(block);
|
let blockTimestamp = timestamp(block);
|
||||||
|
|
||||||
let innerAccumulator = initialInnerAccumulator;
|
let innerAccumulator = initialInnerAccumulator;
|
||||||
@@ -371,13 +321,13 @@ async function buildRewardEvents<A>(
|
|||||||
account.toString(),
|
account.toString(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const eventId = eventIdFromBlockAndIdx(blockNumber, eventIndex.toString());
|
const evtId = eventIdFromBlockAndIdx(blockNum, eventIndex.toString());
|
||||||
|
|
||||||
const accountAddress = account.toString();
|
const accountAddress = account.toString();
|
||||||
const destinationAddress = accountsMapping[accountAddress];
|
const destinationAddress = accountsMapping[accountAddress];
|
||||||
|
|
||||||
const element = new HistoryElement(
|
const element = new HistoryElement(
|
||||||
eventId,
|
evtId,
|
||||||
block.block.header.number.toNumber(),
|
block.block.header.number.toNumber(),
|
||||||
blockTimestamp,
|
blockTimestamp,
|
||||||
destinationAddress !== undefined ? destinationAddress : accountAddress,
|
destinationAddress !== undefined ? destinationAddress : accountAddress,
|
||||||
@@ -407,7 +357,7 @@ async function updateAccumulatedReward(
|
|||||||
return await updateAccumulatedGenericReward(
|
return await updateAccumulatedGenericReward(
|
||||||
AccumulatedReward,
|
AccumulatedReward,
|
||||||
accountId.toString(),
|
accountId.toString(),
|
||||||
(amount as unknown as Balance).toBigInt(),
|
(amount as any).toBigInt(),
|
||||||
isReward,
|
isReward,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -425,7 +375,7 @@ async function updateAccountRewards(
|
|||||||
accountAddress,
|
accountAddress,
|
||||||
blockNumber(event),
|
blockNumber(event),
|
||||||
timestamp(event.block),
|
timestamp(event.block),
|
||||||
(amount as unknown as Balance).toBigInt(),
|
(amount as any).toBigInt(),
|
||||||
accumulatedAmount,
|
accumulatedAmount,
|
||||||
rewardType,
|
rewardType,
|
||||||
);
|
);
|
||||||
@@ -463,7 +413,7 @@ async function handleParachainRewardForTxHistory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function handleParachainRewarded(
|
export async function handleParachainRewarded(
|
||||||
rewardEvent: SubstrateEvent<[accountId: Codec, reward: INumber]>,
|
rewardEvent: SubstrateEvent,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await handleParachainRewardForTxHistory(rewardEvent);
|
await handleParachainRewardForTxHistory(rewardEvent);
|
||||||
let accumulatedReward = await updateAccumulatedReward(rewardEvent, true);
|
let accumulatedReward = await updateAccumulatedReward(rewardEvent, true);
|
||||||
@@ -474,46 +424,6 @@ export async function handleParachainRewarded(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============= Mythos ================
|
|
||||||
|
|
||||||
export async function handleMythosRewarded(
|
|
||||||
rewardEvent: SubstrateEvent<[accountId: Codec, reward: INumber]>,
|
|
||||||
): Promise<void> {
|
|
||||||
await handleMythosRewardForTxHistory(rewardEvent);
|
|
||||||
let accumulatedReward = await updateAccumulatedReward(rewardEvent, true);
|
|
||||||
await updateAccountRewards(
|
|
||||||
rewardEvent,
|
|
||||||
RewardType.reward,
|
|
||||||
accumulatedReward.amount,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleMythosRewardForTxHistory(
|
|
||||||
rewardEvent: SubstrateEvent,
|
|
||||||
): Promise<void> {
|
|
||||||
let [account, amount] = decodeDataFromReward(rewardEvent);
|
|
||||||
|
|
||||||
await handleGenericForTxHistory(
|
|
||||||
rewardEvent,
|
|
||||||
account.toString(),
|
|
||||||
async (element: HistoryElement) => {
|
|
||||||
element.reward = {
|
|
||||||
eventIdx: rewardEvent.idx,
|
|
||||||
amount: amount.toString(),
|
|
||||||
isReward: true,
|
|
||||||
stash: account.toString(),
|
|
||||||
// Mythos staking rewards are paid manually by the user so each reward
|
|
||||||
// aggregates multiple payouts, and it is hard to split it into
|
|
||||||
// individual per-session per-validator pieces
|
|
||||||
validator: null,
|
|
||||||
era: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
return element;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============= GENERICS ================
|
// ============= GENERICS ================
|
||||||
|
|
||||||
interface AccumulatedInterface {
|
interface AccumulatedInterface {
|
||||||
@@ -558,12 +468,12 @@ export async function handleGenericForTxHistory(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const extrinsic = event.extrinsic;
|
const extrinsic = event.extrinsic;
|
||||||
const block = event.block;
|
const block = event.block;
|
||||||
const blockNumber = block.block.header.number.toString();
|
const blockNum = block.block.header.number.toString();
|
||||||
const blockTimestamp = timestamp(block);
|
const blockTimestamp = timestamp(block);
|
||||||
const eventId = eventIdFromBlockAndIdx(blockNumber, event.idx.toString());
|
const evtId = eventIdFromBlockAndIdx(blockNum, event.idx.toString());
|
||||||
|
|
||||||
const element = new HistoryElement(
|
const element = new HistoryElement(
|
||||||
eventId,
|
evtId,
|
||||||
block.block.header.number.toNumber(),
|
block.block.header.number.toNumber(),
|
||||||
blockTimestamp,
|
blockTimestamp,
|
||||||
address,
|
address,
|
||||||
@@ -593,20 +503,15 @@ interface AccountRewardsInterface {
|
|||||||
save(): Promise<void>;
|
save(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function eventRecordToSubstrateEvent(
|
export function eventRecordToSubstrateEvent(eventRecord: any): SubstrateEvent {
|
||||||
eventRecord: EventRecord,
|
|
||||||
): SubstrateEvent {
|
|
||||||
return eventRecord as unknown as SubstrateEvent;
|
return eventRecord as unknown as SubstrateEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeDataFromReward(event: SubstrateEvent): [Codec, Codec] {
|
function decodeDataFromReward(event: SubstrateEvent): [any, any] {
|
||||||
// In early version staking.Reward data only have 2 parameters [accountId, amount]
|
|
||||||
// Now rewarded changed to https://polkadot.js.org/docs/substrate/events/#rewardedaccountid32-palletstakingrewarddestination-u128
|
|
||||||
// And we can direct access property from data
|
|
||||||
const {
|
const {
|
||||||
event: { data: innerData },
|
event: { data: innerData },
|
||||||
} = event;
|
} = event;
|
||||||
let account: Codec, amount: Codec;
|
let account: any, amount: any;
|
||||||
if (innerData.length == 2) {
|
if (innerData.length == 2) {
|
||||||
[account, amount] = innerData;
|
[account, amount] = innerData;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+31
-261
@@ -1,6 +1,4 @@
|
|||||||
import { Codec } from "@polkadot/types/types";
|
import { HistoryElement, Transfer } from "../types";
|
||||||
import { HistoryElement } from "../types";
|
|
||||||
import { HistoryElementProps } from "../types/models/HistoryElement";
|
|
||||||
import { SubstrateEvent } from "@subql/types";
|
import { SubstrateEvent } from "@subql/types";
|
||||||
import {
|
import {
|
||||||
blockNumber,
|
blockNumber,
|
||||||
@@ -8,286 +6,58 @@ import {
|
|||||||
calculateFeeAsString,
|
calculateFeeAsString,
|
||||||
timestamp,
|
timestamp,
|
||||||
getEventData,
|
getEventData,
|
||||||
isEvmTransaction,
|
|
||||||
isEvmExecutedEvent,
|
|
||||||
isAssetTxFeePaidEvent,
|
|
||||||
isSwapExecutedEvent,
|
|
||||||
eventRecordToSubstrateEvent,
|
|
||||||
getAssetIdFromMultilocation,
|
|
||||||
BigIntFromCodec,
|
|
||||||
convertOrmlCurrencyIdToString,
|
|
||||||
} from "./common";
|
} from "./common";
|
||||||
|
|
||||||
type TransferPayload = {
|
|
||||||
event: SubstrateEvent;
|
|
||||||
address: Codec;
|
|
||||||
from: Codec;
|
|
||||||
to: Codec;
|
|
||||||
amount: Codec;
|
|
||||||
suffix: string;
|
|
||||||
assetId?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function handleSwap(event: SubstrateEvent): Promise<void> {
|
|
||||||
const [from, to, path, amountIn, amountOut] = getEventData(event);
|
|
||||||
|
|
||||||
let element = await HistoryElement.get(`${eventId(event)}-from`);
|
|
||||||
|
|
||||||
if (element !== undefined) {
|
|
||||||
// already processed swap previously
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let assetIdFee: string;
|
|
||||||
let fee: string;
|
|
||||||
let foundAssetTxFeePaid = event.block.events.find((e) =>
|
|
||||||
isAssetTxFeePaidEvent(eventRecordToSubstrateEvent(e)),
|
|
||||||
);
|
|
||||||
let swaps = event.block.events.filter((e) =>
|
|
||||||
isSwapExecutedEvent(eventRecordToSubstrateEvent(e)),
|
|
||||||
);
|
|
||||||
if (foundAssetTxFeePaid === undefined) {
|
|
||||||
assetIdFee = "native";
|
|
||||||
fee = calculateFeeAsString(event.extrinsic, from.toString());
|
|
||||||
} else {
|
|
||||||
const [who, actualFee, tip, rawAssetIdFee] = getEventData(
|
|
||||||
eventRecordToSubstrateEvent(foundAssetTxFeePaid),
|
|
||||||
);
|
|
||||||
assetIdFee = getAssetIdFromMultilocation(rawAssetIdFee);
|
|
||||||
fee = actualFee.toString();
|
|
||||||
|
|
||||||
let {
|
|
||||||
event: {
|
|
||||||
data: [feeFrom, feeTo, feePath, feeAmountIn, feeAmountOut],
|
|
||||||
},
|
|
||||||
} = swaps[0];
|
|
||||||
|
|
||||||
swaps = swaps.slice(1);
|
|
||||||
if (BigIntFromCodec(actualFee) != BigIntFromCodec(feeAmountIn)) {
|
|
||||||
let {
|
|
||||||
event: {
|
|
||||||
data: [
|
|
||||||
refundFrom,
|
|
||||||
refundTo,
|
|
||||||
refundPath,
|
|
||||||
refundAmountIn,
|
|
||||||
refundAmountOut,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
} = swaps[swaps.length - 1];
|
|
||||||
|
|
||||||
if (
|
|
||||||
BigIntFromCodec(feeAmountIn) ==
|
|
||||||
BigIntFromCodec(actualFee) + BigIntFromCodec(refundAmountOut) &&
|
|
||||||
getAssetIdFromMultilocation((feePath as any)[0]) ==
|
|
||||||
getAssetIdFromMultilocation(
|
|
||||||
(refundPath as any)[(refundPath as any)["length"] - 1],
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
swaps = swaps.slice(swaps.length - 1);
|
|
||||||
// TODO: if fee splitted, than we will process the same block two times
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const swap of swaps) {
|
|
||||||
await processSwap(eventRecordToSubstrateEvent(swap), assetIdFee, fee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function processSwap(
|
|
||||||
event: SubstrateEvent,
|
|
||||||
assetIdFee: string,
|
|
||||||
fee: string,
|
|
||||||
): Promise<void> {
|
|
||||||
const [from, to, path, amountIn, amountOut] = getEventData(event);
|
|
||||||
|
|
||||||
const swap = {
|
|
||||||
assetIdIn: getAssetIdFromMultilocation((path as any)[0]),
|
|
||||||
amountIn: amountIn.toString(),
|
|
||||||
assetIdOut: getAssetIdFromMultilocation(
|
|
||||||
(path as any)[(path as any)["length"] - 1],
|
|
||||||
),
|
|
||||||
amountOut: amountOut.toString(),
|
|
||||||
sender: from.toString(),
|
|
||||||
receiver: to.toString(),
|
|
||||||
assetIdFee: assetIdFee,
|
|
||||||
fee: fee,
|
|
||||||
eventIdx: event.idx,
|
|
||||||
success: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
await createAssetTransmission(event, from.toString(), "-from", {
|
|
||||||
swap: swap,
|
|
||||||
});
|
|
||||||
if (from.toString() != to.toString()) {
|
|
||||||
await createAssetTransmission(event, to.toString(), "-to", { swap: swap });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleTransfer(event: SubstrateEvent): Promise<void> {
|
export async function handleTransfer(event: SubstrateEvent): Promise<void> {
|
||||||
const [from, to, amount] = getEventData(event);
|
const [from, to, amount] = getEventData(event);
|
||||||
|
|
||||||
await createTransfer({
|
await createTransfer(
|
||||||
event,
|
event,
|
||||||
address: from,
|
from.toString(),
|
||||||
from,
|
"-from",
|
||||||
to,
|
from.toString(),
|
||||||
suffix: "-from",
|
to.toString(),
|
||||||
amount,
|
amount.toString(),
|
||||||
});
|
);
|
||||||
await createTransfer({ event, address: to, from, to, suffix: "-to", amount });
|
await createTransfer(
|
||||||
|
event,
|
||||||
|
to.toString(),
|
||||||
|
"-to",
|
||||||
|
from.toString(),
|
||||||
|
to.toString(),
|
||||||
|
amount.toString(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleAssetTransfer(
|
async function createTransfer(
|
||||||
event: SubstrateEvent,
|
event: SubstrateEvent,
|
||||||
|
address: string,
|
||||||
|
suffix: string,
|
||||||
|
from: string,
|
||||||
|
to: string,
|
||||||
|
amount: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const [assetId, from, to, amount] = getEventData(event);
|
const transfer: Transfer = {
|
||||||
|
amount: amount,
|
||||||
await createTransfer({
|
from: from,
|
||||||
event,
|
to: to,
|
||||||
address: from,
|
fee: calculateFeeAsString(event.extrinsic, from),
|
||||||
from,
|
|
||||||
to,
|
|
||||||
suffix: "-from",
|
|
||||||
amount,
|
|
||||||
assetId: assetId.toString(),
|
|
||||||
});
|
|
||||||
await createTransfer({
|
|
||||||
event,
|
|
||||||
address: to,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
suffix: "-to",
|
|
||||||
amount,
|
|
||||||
assetId: assetId.toString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleOrmlTransfer(event: SubstrateEvent): Promise<void> {
|
|
||||||
const [currencyId, from, to, amount] = getEventData(event);
|
|
||||||
|
|
||||||
await createTransfer({
|
|
||||||
event,
|
|
||||||
address: from,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
suffix: "-from",
|
|
||||||
amount,
|
|
||||||
assetId: convertOrmlCurrencyIdToString(currencyId),
|
|
||||||
});
|
|
||||||
await createTransfer({
|
|
||||||
event,
|
|
||||||
address: to,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
suffix: "-to",
|
|
||||||
amount,
|
|
||||||
assetId: convertOrmlCurrencyIdToString(currencyId),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleEquilibriumTransfer(
|
|
||||||
event: SubstrateEvent,
|
|
||||||
): Promise<void> {
|
|
||||||
const [from, to, assetId, amount] = getEventData(event);
|
|
||||||
|
|
||||||
await createTransfer({
|
|
||||||
event,
|
|
||||||
address: from,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
suffix: "-from",
|
|
||||||
amount,
|
|
||||||
assetId: assetId.toString(),
|
|
||||||
});
|
|
||||||
await createTransfer({
|
|
||||||
event,
|
|
||||||
address: to,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
suffix: "-to",
|
|
||||||
amount,
|
|
||||||
assetId: assetId.toString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleTokenTransfer(
|
|
||||||
event: SubstrateEvent,
|
|
||||||
): Promise<void> {
|
|
||||||
await handleOrmlTransfer(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleCurrencyTransfer(
|
|
||||||
event: SubstrateEvent,
|
|
||||||
): Promise<void> {
|
|
||||||
await handleOrmlTransfer(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createTransfer({
|
|
||||||
event,
|
|
||||||
address,
|
|
||||||
suffix,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
amount,
|
|
||||||
assetId = null,
|
|
||||||
}: TransferPayload) {
|
|
||||||
const transfer = {
|
|
||||||
amount: amount.toString(),
|
|
||||||
from: from.toString(),
|
|
||||||
to: to.toString(),
|
|
||||||
fee: calculateFeeAsString(event.extrinsic, from.toString()),
|
|
||||||
eventIdx: event.idx,
|
eventIdx: event.idx,
|
||||||
success: true,
|
success: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let data;
|
|
||||||
if (assetId) {
|
|
||||||
data = {
|
|
||||||
assetTransfer: {
|
|
||||||
...transfer,
|
|
||||||
assetId: assetId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
data = {
|
|
||||||
transfer: transfer,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await createAssetTransmission(event, address, suffix, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createAssetTransmission(
|
|
||||||
event: SubstrateEvent,
|
|
||||||
address: any,
|
|
||||||
suffix: string,
|
|
||||||
data: Partial<HistoryElementProps>,
|
|
||||||
) {
|
|
||||||
const element = new HistoryElement(
|
const element = new HistoryElement(
|
||||||
`${eventId(event)}${suffix}`,
|
`${eventId(event)}${suffix}`,
|
||||||
blockNumber(event),
|
blockNumber(event),
|
||||||
timestamp(event.block),
|
timestamp(event.block),
|
||||||
address.toString(),
|
address,
|
||||||
);
|
);
|
||||||
if (event.extrinsic !== undefined) {
|
|
||||||
if (isEvmTransaction(event.extrinsic.extrinsic.method)) {
|
|
||||||
const executedEvent = event.extrinsic.events.find(isEvmExecutedEvent);
|
|
||||||
element.extrinsicHash =
|
|
||||||
executedEvent?.event.data?.[2]?.toString() ||
|
|
||||||
event.extrinsic.extrinsic.hash.toString();
|
|
||||||
} else {
|
|
||||||
element.extrinsicHash = event.extrinsic.extrinsic.hash.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (event.extrinsic !== undefined) {
|
||||||
|
element.extrinsicHash = event.extrinsic.extrinsic.hash.toString();
|
||||||
element.extrinsicIdx = event.extrinsic.idx;
|
element.extrinsicIdx = event.extrinsic.idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var key in data) {
|
element.transfer = transfer;
|
||||||
(element[key as keyof HistoryElementProps] as any) =
|
|
||||||
data[key as keyof HistoryElementProps];
|
|
||||||
}
|
|
||||||
|
|
||||||
await element.save();
|
await element.save();
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-190
@@ -1,127 +1,35 @@
|
|||||||
import { SubstrateBlock, SubstrateEvent, TypedEventRecord } from "@subql/types";
|
import { SubstrateBlock, SubstrateEvent } from "@subql/types";
|
||||||
import { SubstrateExtrinsic } from "@subql/types";
|
import { SubstrateExtrinsic } from "@subql/types";
|
||||||
import { Balance, EventRecord } from "@polkadot/types/interfaces";
|
|
||||||
import { CallBase } from "@polkadot/types/types/calls";
|
|
||||||
import { AnyTuple, Codec } from "@polkadot/types/types/codec";
|
|
||||||
import { Vec, GenericEventData } from "@polkadot/types";
|
|
||||||
import { INumber } from "@polkadot/types-codec/types/interfaces";
|
|
||||||
import { u8aToHex } from "@polkadot/util";
|
|
||||||
|
|
||||||
const batchCalls = ["batch", "batchAll", "forceBatch"];
|
const batchCalls = ["batch", "batchAll", "forceBatch"];
|
||||||
const transferCalls = ["transfer", "transferKeepAlive"];
|
const transferCalls = ["transfer", "transferKeepAlive"];
|
||||||
const ormlSections = ["currencies", "tokens"];
|
|
||||||
|
|
||||||
export function distinct<T>(array: Array<T>): Array<T> {
|
export function distinct<T>(array: Array<T>): Array<T> {
|
||||||
return [...new Set(array)];
|
return [...new Set(array)];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isBatch(call: CallBase<AnyTuple>): boolean {
|
export function isBatch(call: any): boolean {
|
||||||
return call.section == "utility" && batchCalls.includes(call.method);
|
return call.section == "utility" && batchCalls.includes(call.method);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isProxy(call: CallBase<AnyTuple>): boolean {
|
export function isProxy(call: any): boolean {
|
||||||
return call.section == "proxy" && call.method == "proxy";
|
return call.section == "proxy" && call.method == "proxy";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNativeTransfer(call: CallBase<AnyTuple>): boolean {
|
export function isNativeTransfer(call: any): boolean {
|
||||||
return (
|
return call.section == "balances" && transferCalls.includes(call.method);
|
||||||
(call.section == "balances" && transferCalls.includes(call.method)) ||
|
|
||||||
(call.section == "currencies" && call.method == "transferNativeCurrency")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isAssetTransfer(call: CallBase<AnyTuple>): boolean {
|
export function isNativeTransferAll(call: any): boolean {
|
||||||
return call.section == "assets" && transferCalls.includes(call.method);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isEquilibriumTransfer(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return call.section == "eqBalances" && transferCalls.includes(call.method);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isEvmTransaction(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return call.section === "ethereum" && call.method === "transact";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isEvmExecutedEvent(event: TypedEventRecord<Codec[]>): boolean {
|
|
||||||
return (
|
|
||||||
event.event.section === "ethereum" && event.event.method === "Executed"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isAssetTxFeePaidEvent(event: SubstrateEvent): boolean {
|
|
||||||
return (
|
|
||||||
event.event.section === "assetTxPayment" &&
|
|
||||||
event.event.method === "AssetTxFeePaid"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isCurrencyDepositedEvent(event: SubstrateEvent): boolean {
|
|
||||||
return (
|
|
||||||
event.event.section === "currencies" && event.event.method === "Deposited"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSwapExecutedEvent(event: SubstrateEvent): boolean {
|
|
||||||
return (
|
|
||||||
event.event.section === "assetConversion" &&
|
|
||||||
event.event.method === "SwapExecuted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSwapExactTokensForTokens(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return (
|
|
||||||
call.section === "assetConversion" &&
|
|
||||||
call.method === "swapExactTokensForTokens"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSwapTokensForExactTokens(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return (
|
|
||||||
call.section === "assetConversion" &&
|
|
||||||
call.method === "swapTokensForExactTokens"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHydraOmnipoolBuy(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return call.section === "omnipool" && call.method == "buy";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHydraOmnipoolSell(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return call.section === "omnipool" && call.method == "sell";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHydraRouterBuy(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return call.section === "router" && call.method == "buy";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHydraRouterSell(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return call.section === "router" && call.method == "sell";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOrmlTransfer(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return (
|
|
||||||
ormlSections.includes(call.section) && transferCalls.includes(call.method)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isNativeTransferAll(call: CallBase<AnyTuple>): boolean {
|
|
||||||
return call.section == "balances" && call.method === "transferAll";
|
return call.section == "balances" && call.method === "transferAll";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isOrmlTransferAll(call: CallBase<AnyTuple>): boolean {
|
export function callsFromBatch(batchCall: any): any[] {
|
||||||
return ormlSections.includes(call.section) && call.method === "transferAll";
|
return batchCall.args[0] as any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function callsFromBatch(
|
export function callFromProxy(proxyCall: any): any {
|
||||||
batchCall: CallBase<AnyTuple>,
|
return proxyCall.args[2];
|
||||||
): CallBase<AnyTuple>[] {
|
|
||||||
return batchCall.args[0] as Vec<CallBase<AnyTuple>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function callFromProxy(
|
|
||||||
proxyCall: CallBase<AnyTuple>,
|
|
||||||
): CallBase<AnyTuple> {
|
|
||||||
return proxyCall.args[2] as CallBase<AnyTuple>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function eventIdWithAddress(
|
export function eventIdWithAddress(
|
||||||
@@ -186,12 +94,6 @@ export function calculateFeeAsString(
|
|||||||
const withdrawFee = exportFeeFromBalancesWithdrawEvent(extrinsic, from);
|
const withdrawFee = exportFeeFromBalancesWithdrawEvent(extrinsic, from);
|
||||||
|
|
||||||
if (withdrawFee !== BigInt(0)) {
|
if (withdrawFee !== BigInt(0)) {
|
||||||
if (isEvmTransaction(extrinsic.extrinsic.method)) {
|
|
||||||
const feeRefund = exportFeeRefund(extrinsic, from);
|
|
||||||
return feeRefund
|
|
||||||
? (withdrawFee - feeRefund).toString()
|
|
||||||
: withdrawFee.toString();
|
|
||||||
}
|
|
||||||
return withdrawFee.toString();
|
return withdrawFee.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,51 +107,29 @@ export function calculateFeeAsString(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEventData(event: SubstrateEvent): GenericEventData {
|
export function getEventData(event: SubstrateEvent): any {
|
||||||
return event.event.data as GenericEventData;
|
return event.event.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function eventRecordToSubstrateEvent(
|
export function eventRecordToSubstrateEvent(eventRecord: any): SubstrateEvent {
|
||||||
eventRecord: EventRecord,
|
|
||||||
): SubstrateEvent {
|
|
||||||
return eventRecord as unknown as SubstrateEvent;
|
return eventRecord as unknown as SubstrateEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BigIntFromCodec(eventRecord: Codec): bigint {
|
export function BigIntFromCodec(codec: any): bigint {
|
||||||
return (eventRecord as unknown as INumber).toBigInt();
|
return codec.toBigInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertOrmlCurrencyIdToString(currencyId: Codec): string {
|
export function getRewardData(event: SubstrateEvent): [any, any] {
|
||||||
// make sure first we have scale encoded bytes
|
const {
|
||||||
const bytes = currencyId.toU8a();
|
event: { data: innerData },
|
||||||
|
} = event;
|
||||||
return u8aToHex(bytes).toString();
|
let account: any, amount: any;
|
||||||
}
|
if (innerData.length == 2) {
|
||||||
|
[account, amount] = innerData;
|
||||||
function exportFeeRefund(
|
} else {
|
||||||
extrinsic: SubstrateExtrinsic,
|
[account, , amount] = innerData;
|
||||||
from: string = "",
|
|
||||||
): bigint {
|
|
||||||
const extrinsicSigner = from || extrinsic.extrinsic.signer.toString();
|
|
||||||
|
|
||||||
const eventRecord = extrinsic.events.find(
|
|
||||||
(event) =>
|
|
||||||
event.event.method == "Deposit" &&
|
|
||||||
event.event.section == "balances" &&
|
|
||||||
event.event.data[0].toString() === extrinsicSigner,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (eventRecord != undefined) {
|
|
||||||
const {
|
|
||||||
event: {
|
|
||||||
data: [, fee],
|
|
||||||
},
|
|
||||||
} = eventRecord;
|
|
||||||
|
|
||||||
return (fee as unknown as Balance).toBigInt();
|
|
||||||
}
|
}
|
||||||
|
return [account, amount];
|
||||||
return BigInt(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportFeeFromBalancesWithdrawEvent(
|
function exportFeeFromBalancesWithdrawEvent(
|
||||||
@@ -271,7 +151,7 @@ function exportFeeFromBalancesWithdrawEvent(
|
|||||||
const extrinsicSigner = from || extrinsic.extrinsic.signer.toString();
|
const extrinsicSigner = from || extrinsic.extrinsic.signer.toString();
|
||||||
const withdrawAccountId = accountid.toString();
|
const withdrawAccountId = accountid.toString();
|
||||||
return extrinsicSigner === withdrawAccountId
|
return extrinsicSigner === withdrawAccountId
|
||||||
? (fee as unknown as Balance).toBigInt()
|
? (fee as any).toBigInt()
|
||||||
: BigInt(0);
|
: BigInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +175,7 @@ function exportFeeFromTransactionFeePaidEvent(
|
|||||||
},
|
},
|
||||||
} = eventRecord;
|
} = eventRecord;
|
||||||
|
|
||||||
const fullFee = (fee as Balance).toBigInt() + (tip as Balance).toBigInt();
|
const fullFee = (fee as any).toBigInt() + (tip as any).toBigInt();
|
||||||
|
|
||||||
const extrinsicSigner = from || extrinsic.extrinsic.signer.toString();
|
const extrinsicSigner = from || extrinsic.extrinsic.signer.toString();
|
||||||
const withdrawAccountId = accountid.toString();
|
const withdrawAccountId = accountid.toString();
|
||||||
@@ -319,7 +199,7 @@ function exportFeeFromBalancesDepositEvent(
|
|||||||
},
|
},
|
||||||
} = eventRecord;
|
} = eventRecord;
|
||||||
|
|
||||||
return (fee as unknown as Balance).toBigInt();
|
return (fee as any).toBigInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
return BigInt(0);
|
return BigInt(0);
|
||||||
@@ -339,53 +219,15 @@ function exportFeeFromTreasureDepositEvent(
|
|||||||
},
|
},
|
||||||
} = eventRecord;
|
} = eventRecord;
|
||||||
|
|
||||||
return (fee as unknown as Balance).toBigInt();
|
return (fee as any).toBigInt();
|
||||||
} else {
|
} else {
|
||||||
return BigInt(0);
|
return BigInt(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAssetIdFromMultilocation(
|
export function extractTransactionPaidFee(events: any[]): string | undefined {
|
||||||
multilocation: any,
|
|
||||||
safe = false,
|
|
||||||
): string | undefined {
|
|
||||||
try {
|
|
||||||
let junctions = multilocation.interior;
|
|
||||||
|
|
||||||
if (junctions.isHere) {
|
|
||||||
return "native";
|
|
||||||
} else if (multilocation.parents != "0") {
|
|
||||||
return multilocation.toHex();
|
|
||||||
} else {
|
|
||||||
return junctions.asX2[1].asGeneralIndex.toString();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (safe) {
|
|
||||||
return undefined;
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRewardData(event: SubstrateEvent): [Codec, Codec] {
|
|
||||||
const {
|
|
||||||
event: { data: innerData },
|
|
||||||
} = event;
|
|
||||||
let account: Codec, amount: Codec;
|
|
||||||
if (innerData.length == 2) {
|
|
||||||
[account, amount] = innerData;
|
|
||||||
} else {
|
|
||||||
[account, , amount] = innerData;
|
|
||||||
}
|
|
||||||
return [account, amount];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractTransactionPaidFee(
|
|
||||||
events: EventRecord[],
|
|
||||||
): string | undefined {
|
|
||||||
const eventRecord = events.find(
|
const eventRecord = events.find(
|
||||||
(event) =>
|
(event: any) =>
|
||||||
event.event.method == "TransactionFeePaid" &&
|
event.event.method == "TransactionFeePaid" &&
|
||||||
event.event.section == "transactionPayment",
|
event.event.section == "transactionPayment",
|
||||||
);
|
);
|
||||||
@@ -398,7 +240,7 @@ export function extractTransactionPaidFee(
|
|||||||
},
|
},
|
||||||
} = eventRecord;
|
} = eventRecord;
|
||||||
|
|
||||||
const fullFee = (fee as Balance).toBigInt() + (tip as Balance).toBigInt();
|
const fullFee = (fee as any).toBigInt() + (tip as any).toBigInt();
|
||||||
|
|
||||||
return fullFee.toString();
|
return fullFee.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
import { SubstrateEvent } from "@subql/types";
|
|
||||||
import {
|
|
||||||
BigIntFromCodec,
|
|
||||||
calculateFeeAsString,
|
|
||||||
eventId,
|
|
||||||
eventRecordToSubstrateEvent,
|
|
||||||
getAssetIdFromMultilocation,
|
|
||||||
getEventData,
|
|
||||||
isAssetTxFeePaidEvent,
|
|
||||||
isSwapExecutedEvent,
|
|
||||||
} from "../common";
|
|
||||||
import { HistoryElement } from "../../types";
|
|
||||||
import { createAssetTransmission } from "../Transfers";
|
|
||||||
|
|
||||||
export async function handleAssetConversionSwap(
|
|
||||||
event: SubstrateEvent
|
|
||||||
): Promise<void> {
|
|
||||||
const [from, to, path, amountIn, amountOut] = getEventData(event);
|
|
||||||
|
|
||||||
let element = await HistoryElement.get(`${eventId(event)}-from`);
|
|
||||||
|
|
||||||
if (element !== undefined) {
|
|
||||||
// already processed swap previously
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let assetIdFee: string;
|
|
||||||
let fee: string;
|
|
||||||
let foundAssetTxFeePaid = event.block.events.find((e) =>
|
|
||||||
isAssetTxFeePaidEvent(eventRecordToSubstrateEvent(e))
|
|
||||||
);
|
|
||||||
let swaps = event.block.events.filter((e) =>
|
|
||||||
isSwapExecutedEvent(eventRecordToSubstrateEvent(e))
|
|
||||||
);
|
|
||||||
if (foundAssetTxFeePaid === undefined) {
|
|
||||||
assetIdFee = "native";
|
|
||||||
fee = calculateFeeAsString(event.extrinsic, from.toString());
|
|
||||||
} else {
|
|
||||||
const [who, actualFee, tip, rawAssetIdFee] = getEventData(
|
|
||||||
eventRecordToSubstrateEvent(foundAssetTxFeePaid)
|
|
||||||
);
|
|
||||||
assetIdFee = getAssetIdFromMultilocation(rawAssetIdFee);
|
|
||||||
fee = actualFee.toString();
|
|
||||||
|
|
||||||
let {
|
|
||||||
event: {
|
|
||||||
data: [feeFrom, feeTo, feePath, feeAmountIn, feeAmountOut],
|
|
||||||
},
|
|
||||||
} = swaps[0];
|
|
||||||
|
|
||||||
swaps = swaps.slice(1);
|
|
||||||
if (BigIntFromCodec(actualFee) != BigIntFromCodec(feeAmountIn)) {
|
|
||||||
let {
|
|
||||||
event: {
|
|
||||||
data: [
|
|
||||||
refundFrom,
|
|
||||||
refundTo,
|
|
||||||
refundPath,
|
|
||||||
refundAmountIn,
|
|
||||||
refundAmountOut,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
} = swaps[swaps.length - 1];
|
|
||||||
|
|
||||||
const feePathArray = feePath as unknown as any[];
|
|
||||||
const refundPathArray = refundPath as unknown as any[];
|
|
||||||
|
|
||||||
if (
|
|
||||||
BigIntFromCodec(feeAmountIn) ==
|
|
||||||
BigIntFromCodec(actualFee) + BigIntFromCodec(refundAmountOut) &&
|
|
||||||
getAssetIdFromMultilocation(feePathArray[0]) ==
|
|
||||||
getAssetIdFromMultilocation(
|
|
||||||
refundPathArray[refundPathArray["length"] - 1]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
swaps = swaps.slice(swaps.length - 1);
|
|
||||||
// TODO: if fee splitted, than we will process the same block two times
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const e of swaps) {
|
|
||||||
await processAssetConversionSwap(
|
|
||||||
eventRecordToSubstrateEvent(e),
|
|
||||||
assetIdFee,
|
|
||||||
fee
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function processAssetConversionSwap(
|
|
||||||
event: SubstrateEvent,
|
|
||||||
assetIdFee: string,
|
|
||||||
fee: string
|
|
||||||
): Promise<void> {
|
|
||||||
const [from, to, path, amountIn, amountOut] = getEventData(event);
|
|
||||||
|
|
||||||
const pathArray = path as unknown as any[];
|
|
||||||
|
|
||||||
const swap = {
|
|
||||||
assetIdIn: getAssetIdFromMultilocation(pathArray[0]),
|
|
||||||
amountIn: amountIn.toString(),
|
|
||||||
assetIdOut: getAssetIdFromMultilocation(pathArray[pathArray["length"] - 1]),
|
|
||||||
amountOut: amountOut.toString(),
|
|
||||||
sender: from.toString(),
|
|
||||||
receiver: to.toString(),
|
|
||||||
assetIdFee: assetIdFee,
|
|
||||||
fee: fee,
|
|
||||||
eventIdx: event.idx,
|
|
||||||
success: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
await createAssetTransmission(event, from.toString(), "-from", {
|
|
||||||
swap: swap,
|
|
||||||
});
|
|
||||||
if (from.toString() != to.toString()) {
|
|
||||||
await createAssetTransmission(event, to.toString(), "-to", { swap: swap });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
import { SubstrateEvent, TypedEventRecord } from "@subql/types";
|
|
||||||
import {
|
|
||||||
eventId,
|
|
||||||
eventRecordToSubstrateEvent,
|
|
||||||
extractTransactionPaidFee,
|
|
||||||
isCurrencyDepositedEvent,
|
|
||||||
convertOrmlCurrencyIdToString,
|
|
||||||
} from "../common";
|
|
||||||
import { HistoryElement } from "../../types";
|
|
||||||
import { createAssetTransmission } from "../Transfers";
|
|
||||||
import { AccountId32 } from "@polkadot/types/interfaces/runtime";
|
|
||||||
import { u128, u32 } from "@polkadot/types-codec";
|
|
||||||
import { EventRecord } from "@polkadot/types/interfaces";
|
|
||||||
import { Codec } from "@polkadot/types/types";
|
|
||||||
import { INumber } from "@polkadot/types-codec/types/interfaces";
|
|
||||||
|
|
||||||
type OmnipoolSwapArgs = [
|
|
||||||
who: AccountId32,
|
|
||||||
assetIn: u32,
|
|
||||||
assetOut: u32,
|
|
||||||
amountIn: u128,
|
|
||||||
amountOut: u128,
|
|
||||||
assetFeeAmount: u128,
|
|
||||||
protocolFeeAmount: u128,
|
|
||||||
];
|
|
||||||
|
|
||||||
type RouterSwapArgs = [
|
|
||||||
assetIn: u32,
|
|
||||||
assetOut: u32,
|
|
||||||
amountIn: u128,
|
|
||||||
amountOut: u128,
|
|
||||||
];
|
|
||||||
|
|
||||||
export async function handleOmnipoolSwap(
|
|
||||||
event: SubstrateEvent<OmnipoolSwapArgs>,
|
|
||||||
): Promise<void> {
|
|
||||||
let element = await HistoryElement.get(`${eventId(event)}-from`);
|
|
||||||
if (element !== undefined) {
|
|
||||||
// already processed swap previously
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (event.extrinsic == undefined) {
|
|
||||||
// TODO we dont yet process swap events that were initiated by the system and not by the user
|
|
||||||
// Example: https://hydradx.subscan.io/block/4361343?tab=event&event=4361343-27
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPartOfRouterSwap(event.extrinsic.events)) {
|
|
||||||
// TODO: we currently don't support swaps in batch
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fee = findHydraDxFeeTyped(event.extrinsic.events);
|
|
||||||
const [who, assetIn, assetOut, amountIn, amountOut] = event.event.data;
|
|
||||||
|
|
||||||
const swap = {
|
|
||||||
assetIdIn: convertHydraDxTokenIdToString(assetIn),
|
|
||||||
amountIn: amountIn.toString(),
|
|
||||||
assetIdOut: convertHydraDxTokenIdToString(assetOut),
|
|
||||||
amountOut: amountOut.toString(),
|
|
||||||
sender: who.toString(),
|
|
||||||
receiver: who.toString(),
|
|
||||||
assetIdFee: fee.tokenId,
|
|
||||||
fee: fee.amount,
|
|
||||||
eventIdx: event.idx,
|
|
||||||
success: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const blockNumber = event.block.block.header.number;
|
|
||||||
logger.info(
|
|
||||||
`Constructed omnipool swap ${JSON.stringify(
|
|
||||||
swap,
|
|
||||||
)} for block ${blockNumber.toString()}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
await createAssetTransmission(event, who.toString(), "-from", { swap: swap });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleHydraRouterSwap(
|
|
||||||
event: SubstrateEvent<RouterSwapArgs>,
|
|
||||||
): Promise<void> {
|
|
||||||
let element = await HistoryElement.get(`${eventId(event)}-from`);
|
|
||||||
if (element !== undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (event.extrinsic == undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const who = event.extrinsic.extrinsic.signer.toString();
|
|
||||||
const fee = findHydraDxFeeTyped(event.extrinsic.events);
|
|
||||||
const [assetIn, assetOut, amountIn, amountOut] = event.event.data;
|
|
||||||
|
|
||||||
const swap = {
|
|
||||||
assetIdIn: convertHydraDxTokenIdToString(assetIn),
|
|
||||||
amountIn: amountIn.toString(),
|
|
||||||
assetIdOut: convertHydraDxTokenIdToString(assetOut),
|
|
||||||
amountOut: amountOut.toString(),
|
|
||||||
sender: who.toString(),
|
|
||||||
receiver: who.toString(),
|
|
||||||
assetIdFee: fee.tokenId,
|
|
||||||
fee: fee.amount,
|
|
||||||
eventIdx: event.idx,
|
|
||||||
success: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const blockNumber = event.block.block.header.number;
|
|
||||||
logger.info(
|
|
||||||
`Constructed router swap ${JSON.stringify(
|
|
||||||
swap,
|
|
||||||
)} for block ${blockNumber.toString()}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
await createAssetTransmission(event, who.toString(), "-from", { swap: swap });
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Fee = {
|
|
||||||
tokenId: string;
|
|
||||||
amount: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function findHydraDxFeeTyped(events: TypedEventRecord<Codec[]>[]): Fee {
|
|
||||||
return findHydraDxFee(events as EventRecord[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function findHydraDxFee(events: EventRecord[]): Fee {
|
|
||||||
const lastCurrenciesDepositEvent = findLastEvent(events, (event) =>
|
|
||||||
isCurrencyDepositedEvent(eventRecordToSubstrateEvent(event)),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (lastCurrenciesDepositEvent == undefined) return findNativeFee(events);
|
|
||||||
|
|
||||||
const {
|
|
||||||
event: {
|
|
||||||
data: [currencyId, _, amount],
|
|
||||||
},
|
|
||||||
} = lastCurrenciesDepositEvent;
|
|
||||||
|
|
||||||
return {
|
|
||||||
tokenId: convertHydraDxTokenIdToString(currencyId),
|
|
||||||
amount: (amount as INumber).toString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPartOfRouterSwap(events: TypedEventRecord<Codec[]>[]): boolean {
|
|
||||||
const eventRecords = events as EventRecord[];
|
|
||||||
for (const eventRecord of eventRecords) {
|
|
||||||
if (
|
|
||||||
eventRecord.event.section == "router" &&
|
|
||||||
(eventRecord.event.method == "Executed" ||
|
|
||||||
eventRecord.event.method == "RouteExecuted")
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNativeFee(events: EventRecord[]): Fee {
|
|
||||||
let foundAssetTxFeePaid = extractTransactionPaidFee(events);
|
|
||||||
if (foundAssetTxFeePaid == undefined) foundAssetTxFeePaid = "0";
|
|
||||||
|
|
||||||
return {
|
|
||||||
tokenId: "native",
|
|
||||||
amount: foundAssetTxFeePaid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertHydraDxTokenIdToString(hydraDxTokenId: Codec): string {
|
|
||||||
const asString = hydraDxTokenId.toString();
|
|
||||||
|
|
||||||
if (asString == "0") {
|
|
||||||
return "native";
|
|
||||||
} else {
|
|
||||||
return convertOrmlCurrencyIdToString(hydraDxTokenId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findLastEvent(
|
|
||||||
events: EventRecord[],
|
|
||||||
expression: (event: EventRecord) => boolean,
|
|
||||||
): EventRecord | undefined {
|
|
||||||
const currenciesDepositedEvents = events.filter(expression);
|
|
||||||
|
|
||||||
if (currenciesDepositedEvents.length == 0) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return currenciesDepositedEvents[currenciesDepositedEvents.length - 1];
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
//Exports all handler functions
|
|
||||||
export * from "./AssetConversion";
|
|
||||||
export * from "./HydraDx";
|
|
||||||
import "@polkadot/api-augment";
|
|
||||||
+17
-1
@@ -7,12 +7,28 @@
|
|||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"target": "es2020",
|
"target": "es2020",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strictNullChecks": false,
|
"strictNullChecks": false,
|
||||||
"strict": true
|
"strict": true,
|
||||||
|
"paths": {
|
||||||
|
"@polkadot/types": ["./node_modules/@pezkuwi/types/cjs/index.d.ts"],
|
||||||
|
"@polkadot/types/*": ["./node_modules/@pezkuwi/types/cjs/*"],
|
||||||
|
"@polkadot/types-codec": ["./node_modules/@pezkuwi/types-codec/cjs/index.d.ts"],
|
||||||
|
"@polkadot/types-codec/*": ["./node_modules/@pezkuwi/types-codec/cjs/*"],
|
||||||
|
"@polkadot/api": ["./node_modules/@pezkuwi/api/cjs/index.d.ts"],
|
||||||
|
"@polkadot/api/*": ["./node_modules/@pezkuwi/api/cjs/*"],
|
||||||
|
"@pezkuwi/types": ["./node_modules/@pezkuwi/types/cjs/index.d.ts"],
|
||||||
|
"@pezkuwi/types/*": ["./node_modules/@pezkuwi/types/cjs/*"],
|
||||||
|
"@pezkuwi/types-codec": ["./node_modules/@pezkuwi/types-codec/cjs/index.d.ts"],
|
||||||
|
"@pezkuwi/types-codec/*": ["./node_modules/@pezkuwi/types-codec/cjs/*"],
|
||||||
|
"@pezkuwi/api": ["./node_modules/@pezkuwi/api/cjs/index.d.ts"],
|
||||||
|
"@pezkuwi/api/*": ["./node_modules/@pezkuwi/api/cjs/*"]
|
||||||
|
},
|
||||||
|
"baseUrl": "."
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*",
|
"src/**/*",
|
||||||
|
|||||||
Reference in New Issue
Block a user