Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions dexs/pactswap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { FetchOptions, FetchV2, SimpleAdapter } from "../../adapters/types";
import { fetchVolumeFromPactswapAPI, PACTSWAP_SUPPORTED_CHAINS } from "./pactswap";

const fetch: FetchV2 = async (options: FetchOptions) => {
const timeframes = await fetchVolumeFromPactswapAPI(options.chain, options.startTimestamp, options.endTimestamp);

const dailyVolume = options.createBalances();
timeframes.forEach(({ volume }) => {
dailyVolume.addUSDValue(Number(volume));
});

return {
dailyVolume,
};
};

const adapter: SimpleAdapter = {
version: 2,
fetch,
chains: Array.from(PACTSWAP_SUPPORTED_CHAINS)
};

export default adapter;
56 changes: 56 additions & 0 deletions dexs/pactswap/pactswap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import fetchURL from "../../utils/fetchURL";
import { CHAIN } from "../../helpers/chains";

export const PACTSWAP_SUPPORTED_CHAINS = [
CHAIN.BSC,
CHAIN.BITCOIN,
CHAIN.DOGE,
CHAIN.ETHEREUM,
CHAIN.LITECOIN,
CHAIN.POLYGON,
CHAIN.TRON,
] as const;

const INDEXER_URL = "https://pactswap-indexer.coinhq.store/api/v1/metrics/";

// CAIP-122 chain IDs to bigint for Bitcoin like chains
// # Bitcoin mainnet (see https://github.com/bitcoin/bips/blob/master/bip-0122.mediawiki#definition-of-chain-id)
// bip122:000000000019d6689c085ae165831e93
// # Litecoin mainnet
// bip122:12a765e31ffd4059bada1e25190f6e98
// # Dogecoin mainnet
const PACTSWAP_CHAIN_ID_MAP: Record<typeof PACTSWAP_SUPPORTED_CHAINS[number], bigint> = {
[CHAIN.BSC]: 56n,
[CHAIN.BITCOIN]: BigInt("0x".concat("000000000019d6689c085ae165831e93")),
[CHAIN.DOGE]: BigInt("0x".concat("1a91e3dace36e2be3bf030a65679fe82")),
[CHAIN.ETHEREUM]: 1n,
[CHAIN.LITECOIN]: BigInt("0x".concat("12a765e31ffd4059bada1e25190f6e98")),
[CHAIN.POLYGON]: 137n,
[CHAIN.TRON]: 128n,
};

export const fetchVolumeFromPactswapAPI = async (
chain: string,
startTimestamp: number,
endTimestamp: number
): Promise<Array<{
timestamp: string;
volume: string;
}>> => {
const chainId = PACTSWAP_CHAIN_ID_MAP[chain];
try {
const response = await fetchURL(
`${INDEXER_URL}swaps/timeseries/volume?chain_id=${chainId}&timestamp_gt=${startTimestamp}&timestamp_lt=${endTimestamp}&interval=day`
) as Array<{
timestamp: string;
volume: string;
}>;
return response
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
.slice(0, 2)
.filter(Boolean);
} catch (error) {
console.error(error);
return [];
}
};
144 changes: 144 additions & 0 deletions fees/pactswap/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { gql, request } from "graphql-request"

const COINWEB_URL = 'https://api-cloud.coinweb.io'
const queryCount = gql`
query(
$start: NaiveDateTime
$end: NaiveDateTime
$feeSmartContract: String
) {
network(net: BNB) {
countClaims(
issuer: {
FromSmartContract: $feeSmartContract
}
firstPartOfKey: ["FUNDS"]
datetimeRange: { from: $start, to: $end }
)
}
}
`

type QueryFee = {
network: {
fetchClaims: {
claims: Array<{
blockInfo: FeeClaimBlockInfo
claim: FeeClaimClaim
}>
hasNextPage: boolean
nextPageAnchor: {
hash: string
height: number
}
}
}
}

type FeeClaimBlockInfo = {
height: number
time: string
hash: string
}
type FeeClaimClaim = {
content: {
body: string
feesStored: `0x${string}`
key: string
}
}
const queryFee = gql`
query (
$feeSmartContract: String!
$start: NaiveDateTime
$end: NaiveDateTime
$countToReturn: Int!
) {
network(net: BNB) {
fetchClaims(
issuer: { FromSmartContract: $feeSmartContract }
firstPartOfKey: ["FUNDS"]
maxClaimsToReturn: $countToReturn
datetimeRange: { from: $start, to: $end }
) {
claims {
blockInfo {
height
time
hash
}
claim {
content {
body
feesStored
key
}
issuer
}
}
hasNextPage
nextPageAnchor {
hash
height
}
}
}
}`

export const getFeeSmartContract = async(): Promise<string> => {
const data = await fetch('https://app.pactswap.io/build-info.json')
const json = await data.json()
try {
const feeSmartContract = json.BTC.L2_CONTRACT_ADDRESS_MAKER.module.instance.parameters.content.owner;
return feeSmartContract
} catch (error) {
throw new Error('Failed to get fee smart contract', { cause: error })
}
}

export const getFeeClaimsCount = async(feeSmartContract: string, startTime: string, endTime: string): Promise<number> => {
const countResponse = await request(COINWEB_URL, queryCount, {
start: startTime,
end: endTime,
feeSmartContract: feeSmartContract,
});

const count = countResponse.network.countClaims;
return Number(count);
}

const getFeeClaims = async(feeSmartContract: string, startTime: string, endTime: string, countToReturn: number) => {
const feeResponse = await request<QueryFee>(COINWEB_URL, queryFee, {
start: startTime,
end: endTime,
feeSmartContract: feeSmartContract,
countToReturn: countToReturn,
});
return feeResponse.network.fetchClaims;
}

export const oneDayInSeconds = 86400;

export const getFee = async(feeSmartContract: string, startTime: string, endTime: string, countToReturn: number): Promise<number> => {
const feeClaims = await getFeeClaims(feeSmartContract, startTime, endTime, countToReturn);
if (feeClaims.claims.length === 1) {
return Number(feeClaims.claims[0].claim.content.feesStored);
}

let nearesToEndTime: typeof feeClaims.claims[0] | undefined = undefined;

for (const claim of feeClaims.claims) {
if (new Date(claim.blockInfo.time) <= new Date(startTime)) {
nearesToEndTime = claim;
}
}

const bottomClaim = nearesToEndTime || feeClaims.claims[0];
const bottomFee = Number(bottomClaim.claim.content.feesStored);

const latesFeeClaim = feeClaims.claims.at(-1);
const latestFee = Number(latesFeeClaim?.claim.content.feesStored);

const fee = latestFee - bottomFee;
return fee;
}
49 changes: 49 additions & 0 deletions fees/pactswap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { FetchOptions, FetchV2, SimpleAdapter } from "../../adapters/types";
import { CHAIN } from "../../helpers/chains";
import { getFee, getFeeClaimsCount, getFeeSmartContract, oneDayInSeconds } from "./helpers";

const fetch: FetchV2 = async (options: FetchOptions) => {
const dailyFees = options.createBalances();
const feeSmartContract = await getFeeSmartContract();
const formattedFeeSmartContract = feeSmartContract.startsWith('0x') ? feeSmartContract : `0x${feeSmartContract}`;

let startTime = new Date(options.fromTimestamp * 1000).toISOString().replace('Z', '');
const endTime = new Date(options.toTimestamp * 1000).toISOString().replace('Z', '');

let count = await getFeeClaimsCount(formattedFeeSmartContract, startTime, endTime);

if (!count) {
return { dailyFees }
}

const maxDays = 30;
let currentDays = 0;

while (count === 1 && currentDays < maxDays) {
startTime = new Date(new Date(startTime).getTime() - oneDayInSeconds * 1000 * (currentDays + 1)).toISOString().replace('Z', '');
count = await getFeeClaimsCount(formattedFeeSmartContract, startTime, endTime);
currentDays++;
}

const fee = await getFee(formattedFeeSmartContract, startTime, endTime, count);

dailyFees.addGasToken(BigInt(fee).toString());

return { dailyFees }
};

const adapter: SimpleAdapter = {
version: 2,
adapter: {
[CHAIN.COINWEB]: {
fetch,
}
},
methodology: {
Fees: 'All fees paid by users for finalising transactions.',
Revenue: 'All fees are distributed to PactSwap fee pool.',
ProtocolRevenue: 'All fees are distributed to PactSwap fee pool.',
}
};

export default adapter;
1 change: 1 addition & 0 deletions helpers/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,5 @@ export enum CHAIN {
HIBACHI = "hibachi",
SATORI = "satori",
SHIBARIUM = "shibarium",
COINWEB = "coinweb",
}
Loading