@cryptodevops/n8n-nodes-bitquery-api
Version:
Nœud n8n pour les APIs Raydium et PumpFun - Accès aux données des pools et tokens Solana sur les DEX Raydium et PumpFun
561 lines (560 loc) • 19.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BitqueryApi = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const axios_1 = __importDefault(require("axios"));
class BitqueryApi {
constructor() {
this.description = {
displayName: 'Bitquery API',
name: 'bitqueryApi',
icon: 'file:bitquery.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["queryType"]}}',
description: 'Accède aux données blockchain multi-chaînes via l\'API Bitquery - Transactions, UTXO, statistiques réseau',
defaults: {
name: 'Bitquery API',
},
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
inputs: ["main" /* NodeConnectionType.Main */],
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
outputs: ["main" /* NodeConnectionType.Main */],
credentials: [
{
name: 'bitqueryApi',
required: true,
},
],
properties: [
{
displayName: 'Type De Requête',
name: 'queryType',
type: 'options',
noDataExpression: true,
default: 'raydium_latest_pools',
options: [
{
name: 'PumpFun API - Top 10 Tokens By Marketcap Change In Last 5 Mins',
value: 'pumpfun_marketcap_change',
description: 'Récupère le top 10 des tokens Pump Fun par changement de marketcap dans les 5 dernières minutes',
},
{
name: 'PumpFun API - Top 100 About To Graduate Pump Fun Tokens',
value: 'pumpfun_graduating_tokens',
description: 'Récupère le top 100 des tokens sur le point de graduer de Pump Fun',
},
{
name: 'Raydium API - Latest Pools Created On Launchpad',
value: 'raydium_launchpad_pools',
description: 'Récupère les derniers pools créés sur le launchpad Raydium',
},
{
name: 'Raydium API - Latest Pools Created On Raydium',
value: 'raydium_latest_pools',
description: 'Récupère les derniers pools créés sur Raydium',
},
{
name: 'Raydium API - Latest Trades For A Specific Currency',
value: 'raydium_latest_trades',
description: 'Récupère les derniers trades pour une devise spécifique sur Raydium',
},
{
name: 'Raydium API - Top 100 About To Graduate Launchpad Tokens',
value: 'raydium_graduating_tokens',
description: 'Récupère le top 100 des tokens sur le point de graduer du launchpad Raydium',
},
],
},
{
displayName: 'Program Method',
name: 'programMethod',
type: 'string',
default: 'initializeUserWithNonce',
description: 'The program method to filter by',
displayOptions: {
show: {
queryType: ['raydium_latest_pools'],
},
},
},
{
displayName: 'Program Address',
name: 'programAddress',
type: 'string',
default: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
description: 'The program address to filter by',
displayOptions: {
show: {
queryType: ['raydium_latest_pools'],
},
},
},
{
displayName: 'Currency Mint Address',
name: 'currencyMintAddress',
type: 'string',
default: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
description: 'The mint address of the currency to filter trades',
displayOptions: {
show: {
queryType: ['raydium_latest_trades'],
},
},
},
{
displayName: 'Trade Limit',
name: 'tradeLimit',
type: 'number',
default: 10,
description: 'Number of trades to retrieve',
displayOptions: {
show: {
queryType: ['raydium_latest_trades'],
},
},
},
{
displayName: 'Tokens Limit',
name: 'tokensLimit',
type: 'number',
default: 100,
description: 'Number of tokens to retrieve',
displayOptions: {
show: {
queryType: ['raydium_graduating_tokens', 'pumpfun_graduating_tokens'],
},
},
},
{
displayName: 'Top Tokens Limit',
name: 'topTokensLimit',
type: 'number',
default: 10,
description: 'Number of top tokens to retrieve by marketcap change',
displayOptions: {
show: {
queryType: ['pumpfun_marketcap_change'],
},
},
}
],
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
for (let i = 0; i < items.length; i++) {
try {
const queryType = this.getNodeParameter('queryType', i);
const credentials = await this.getCredentials('bitqueryApi');
const baseUrl = 'https://streaming.bitquery.io';
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${credentials.apiKey}`,
};
let query = '';
let variables = {};
switch (queryType) {
case 'raydium_latest_pools':
const programMethod = this.getNodeParameter('programMethod', i);
const programAddress = this.getNodeParameter('programAddress', i);
query = `
subscription {
Solana {
Instructions(
where: {
Transaction: {Result: {Success: true}}
Instruction: {
Program: {
Method: {is: "${programMethod}"}
Address: {is: "${programAddress}"}
}
}
}
) {
Block {
Time
Date
}
Transaction {
Signature
}
Instruction {
AncestorIndexes
CallerIndex
Depth
Data
ExternalSeqNumber
InternalSeqNumber
Index
Accounts {
Address
IsWritable
Token {
Mint
Owner
ProgramId
}
}
CallPath
Logs
Program {
AccountNames
Method
Json
Name
Arguments {
Type
Name
Value {
__typename
... on Solana_ABI_Integer_Value_Arg {
integer
}
... on Solana_ABI_String_Value_Arg {
string
}
... on Solana_ABI_Address_Value_Arg {
address
}
... on Solana_ABI_BigInt_Value_Arg {
bigInteger
}
... on Solana_ABI_Bytes_Value_Arg {
hex
}
... on Solana_ABI_Boolean_Value_Arg {
bool
}
... on Solana_ABI_Float_Value_Arg {
float
}
... on Solana_ABI_Json_Value_Arg {
json
}
}
}
}
}
}
}
}
`;
break;
case 'raydium_latest_trades':
const currencyMintAddress = this.getNodeParameter('currencyMintAddress', i);
const tradeLimit = this.getNodeParameter('tradeLimit', i);
query = `
query {
Solana {
Buyside: DEXTrades(
limit:{count:${tradeLimit}}
orderBy:{descending:Block_Time}
where: {Trade: {Buy: {Currency: {MintAddress: {is: "${currencyMintAddress}"}}}, Dex: {ProgramAddress: {is: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"}}}}
) {
Trade {
Dex {
ProgramAddress
ProtocolFamily
ProtocolName
}
Buy {
Account {
Address
}
Amount
Currency {
Decimals
Symbol
MintAddress
Name
}
PriceAgaistSellCurrency: Price
}
Sell {
Account {
Address
}
Amount
Currency {
Decimals
Symbol
MintAddress
Name
}
PriceAgaistBuyCurrency: Price
}
}
Block {
Time
Height
}
Transaction {
Signature
FeePayer
Signer
}
}
Sellside: DEXTrades(
limit:{count:${tradeLimit}}
orderBy:{descending:Block_Time}
where: {Trade: {Sell: {Currency: {MintAddress: {is: "${currencyMintAddress}"}}}, Dex: {ProgramAddress: {is: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"}}}}
) {
Trade {
Dex {
ProgramAddress
ProtocolFamily
ProtocolName
}
Buy {
Account {
Address
}
Amount
Currency {
Decimals
Symbol
MintAddress
Name
}
PriceAgaistSellCurrency: Price
}
Sell {
Account {
Address
}
Amount
Currency {
Decimals
Symbol
MintAddress
Name
}
PriceAgaistBuyCurrency: Price
}
}
Block {
Time
Height
}
Transaction {
Signature
FeePayer
Signer
}
}
}
}
`;
break;
case 'raydium_launchpad_pools':
query = `
{
Solana(network: solana, dataset: realtime) {
Instructions(
where: {Instruction: {Program: {Address: {is: "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"}, Method: {is: "PoolCreateEvent"}}}}
orderBy: {descending: Block_Time}
) {
Instruction {
Accounts {
Address
}
Program {
Name
Method
AccountNames
Arguments {
Name
Type
Value {
... on Solana_ABI_Integer_Value_Arg {
integer
}
... on Solana_ABI_String_Value_Arg {
string
}
... on Solana_ABI_Address_Value_Arg {
address
}
... on Solana_ABI_BigInt_Value_Arg {
bigInteger
}
... on Solana_ABI_Bytes_Value_Arg {
hex
}
... on Solana_ABI_Boolean_Value_Arg {
bool
}
... on Solana_ABI_Float_Value_Arg {
float
}
... on Solana_ABI_Json_Value_Arg {
json
}
}
}
}
}
}
}
}
`;
break;
case 'raydium_graduating_tokens':
const tokensLimit = this.getNodeParameter('tokensLimit', i);
query = `
{
Solana {
DEXPools(
limitBy: {by: Pool_Market_BaseCurrency_MintAddress, count: 1}
limit: {count: ${tokensLimit}}
orderBy: {ascending: Pool_Base_PostAmount}
where: {Pool: {Base: {PostAmount: {gt: "206900000"}}, Dex: {ProgramAddress: {is: "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"}}, Market: {QuoteCurrency: {MintAddress: {in: ["11111111111111111111111111111111", "So11111111111111111111111111111111111111112"]}}}}, Transaction: {Result: {Success: true}}, Block: {Time: {since_relative:{minutes_ago:5}}}}
) {
Bonding_Curve_Progress_precentage: calculate(expression:"100 - ((($Pool_Base_Balance - 206900000) * 100) / 793100000)")
Pool {
Market {
BaseCurrency {
MintAddress
Name
Symbol
}
MarketAddress
QuoteCurrency {
MintAddress
Name
Symbol
}
}
Dex {
ProtocolName
ProtocolFamily
}
Base {
Balance: PostAmount(maximum: Block_Time)
}
Quote {
PostAmount
PriceInUSD
PostAmountInUSD
}
}
}
}
}
`;
break;
case 'pumpfun_graduating_tokens':
const pumpfunTokensLimit = this.getNodeParameter('tokensLimit', i);
query = `
{
Solana {
DEXPools(
limitBy: {by: Pool_Market_BaseCurrency_MintAddress, count: 1}
limit: {count: ${pumpfunTokensLimit}}
orderBy: {ascending: Pool_Base_PostAmount}
where: {Pool: {Base: {PostAmount: {gt: "206900000"}}, Dex: {ProgramAddress: {is: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"}}, Market: {QuoteCurrency: {MintAddress: {in: ["11111111111111111111111111111111", "So11111111111111111111111111111111111111112"]}}}}, Transaction: {Result: {Success: true}}, Block: {Time: {since_relative:{minutes_ago:5}}}}
) {
Bonding_Curve_Progress_precentage: calculate(expression:"100 - ((($Pool_Base_Balance - 206900000) * 100) / 793100000)")
Pool {
Market {
BaseCurrency {
MintAddress
Name
Symbol
}
MarketAddress
QuoteCurrency {
MintAddress
Name
Symbol
}
}
Dex {
ProtocolName
ProtocolFamily
}
Base {
Balance: PostAmount(maximum: Block_Time)
}
Quote {
PostAmount
PriceInUSD
PostAmountInUSD
}
}
}
}
}
`;
break;
case 'pumpfun_marketcap_change':
const topTokensLimit = this.getNodeParameter('topTokensLimit', i);
query = `
query MyQuery {
Solana {
DEXTradeByTokens(
limit: {count: ${topTokensLimit}}
orderBy:{descendingByField:"Marketcap_Change_5min"}
where: {Trade: {Dex: {ProgramAddress: {is: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"}}}, Transaction: {Result: {Success: true}}, Block: {Time: {since_relative: {hours_ago: 6}}}}
) {
Trade {
Currency {
Name
Symbol
MintAddress
}
Price_5min_ago: PriceInUSD(minimum:Block_Time if:{Block:{Time:{since_relative:{minutes_ago:5}}}})
Price_1h_ago: PriceInUSD(minimum:Block_Time if:{Block:{Time:{since_relative:{hours_ago:1}}}})
Price_6h_ago: PriceInUSD(minimum: Block_Time)
CurrentPrice: PriceInUSD(maximum: Block_Time)
Side {
Currency {
Name
Symbol
MintAddress
}
}
}
Marketcap_Change_5min: calculate(expression: "(($Trade_CurrentPrice - $Trade_Price_5min_ago) / $Trade_Price_5min_ago) * 100")
Marketcap_Change_1h: calculate(expression: "(($Trade_CurrentPrice - $Trade_Price_1h_ago) / $Trade_Price_1h_ago) * 100")
Marketcap_Change_6h: calculate(expression: "(($Trade_CurrentPrice - $Trade_Price_6h_ago) / $Trade_Price_6h_ago) * 100")
}
}
}
`;
break;
default:
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Type de requête non supporté: ${queryType}`, { itemIndex: i });
}
const response = await axios_1.default.post(`${baseUrl}/eap`, {
query: query,
variables: variables,
}, { headers });
if (response.data.errors) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Erreur API Bitquery: ${JSON.stringify(response.data.errors)}`, { itemIndex: i });
}
returnData.push({
json: response.data.data,
pairedItem: { item: i },
});
}
catch (error) {
if (this.continueOnFail()) {
returnData.push({
json: { error: error.message },
pairedItem: { item: i },
});
continue;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i });
}
}
return [returnData];
}
}
exports.BitqueryApi = BitqueryApi;