Skip to content

Commit

Permalink
add code (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
amilz authored Sep 13, 2024
1 parent e87b53e commit 73bd778
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 1 deletion.
2 changes: 1 addition & 1 deletion solana/web3.js-2.0/basics/transferSol.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Guide walkthrough:
// Guide walkthrough: How to Send Transactions with Solana Web3.js 2.0
// https://www.quicknode.com/guides/solana-development/solana-web3.js-2.0/transfer-sol

import {
Expand Down
3 changes: 3 additions & 0 deletions solana/web3.js-2.0/fungibles/fungibles.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Source code for Guide: Creating a Fungible Token with Solana Web3.js 2.0
// https://www.quicknode.com/guides/solana-development/tooling/web3-2/fungibles

import { getCreateAccountInstruction } from "@solana-program/system";
import {
findAssociatedTokenPda,
Expand Down
67 changes: 67 additions & 0 deletions solana/web3.js-2.0/quicknode-addons/guide1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Source code for Guide: How to Use QuickNode Add-ons using Solana Web3.js 2.0 (Part 1)
// https://www.quicknode.com/guides/solana-development/tooling/web3-2/qn-add-ons

import {
Rpc,
createDefaultRpcTransport,
createRpc,
RpcTransport,
createRpcApi,
createSolanaRpcApi,
} from "@solana/web3.js";
import {
EstimatePriorityFeesResponse,
EstimatePriorityFeesParams
} from "./types";

type PriorityFeeApi = {
qn_estimatePriorityFees(params: EstimatePriorityFeesParams): EstimatePriorityFeesResponse;
}

interface createQuickNodeTransportParams {
endpoint: string;
}

function createQuickNodeTransport({ endpoint }: createQuickNodeTransportParams): RpcTransport {
const jsonRpcTransport = createDefaultRpcTransport({ url: endpoint });

return async <TResponse>(...args: Parameters<RpcTransport>): Promise<TResponse> => {
return await jsonRpcTransport(...args);
};
}

/**
*
* @param endpoint - Solana HTTP Endpoint
* Establish connection to Solana cluster
* Change as needed to the network you're using.
* Get a free Devnet or Mainnet endpoint from:
* https://www.quicknode.com/signup?utm_source=internal&utm_campaign=sample-apps&utm_content=solana-web3.js-2.0-add-ons
* @returns RPC instance with priority fee API
*/
export function createPriorityFeeApi(endpoint: string): Rpc<PriorityFeeApi> {
const api0 = createSolanaRpcApi();
const api = createRpcApi<PriorityFeeApi>({
parametersTransformer: (params: any[]) => params[0],
responseTransformer: (response: any) => response.result,
});
const transport = createQuickNodeTransport({
endpoint,
});
return createRpc({ api, transport });
}



async function main() {
const quickNodeRpc = createPriorityFeeApi('https://example.solana-mainnet.quiknode.pro/123456/');

const priorityFees = await quickNodeRpc.qn_estimatePriorityFees({
account: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
last_n_blocks: 100
}).send();

console.log(priorityFees);
}

main();
185 changes: 185 additions & 0 deletions solana/web3.js-2.0/quicknode-addons/guide2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Source code for Guide: How to Use QuickNode Add-ons using Solana Web3.js 2.0 (Part 2)
// https://www.quicknode.com/guides/solana-development/tooling/web3-2/qn-add-ons-2

import {
Rpc,
createDefaultRpcTransport,
createRpc,
RpcTransport,
createRpcApi,
} from "@solana/web3.js";
import {
EstimatePriorityFeesResponse,
EstimatePriorityFeesParams,
IpfsUploadRequest,
IpfsUploadResponse,
QuoteGetRequest, QuoteResponse
} from "./types";
import * as fs from 'fs';

type PriorityFeeApi = {
qn_estimatePriorityFees(params: EstimatePriorityFeesParams): Promise<EstimatePriorityFeesResponse>;
}

type MetisApi = {
metis_quote(params: QuoteGetRequest): Promise<QuoteResponse>;
// Add other Metis methods here
}

type IpfsApi = {
ipfs_upload(params: IpfsUploadRequest): Promise<IpfsUploadResponse>;
}

type QuickNodeAddons = PriorityFeeApi & MetisApi & IpfsApi;

function createQuickNodeTransport({ endpoint, metisEndpoint, ipfsApiKey }: CreateAddonsApiParams): RpcTransport {
const jsonRpcTransport = createDefaultRpcTransport({ url: endpoint });

return async <TResponse>(...args: Parameters<RpcTransport>): Promise<TResponse> => {
const { method, params } = args[0].payload as { method: string; params: unknown };
switch (true) {
case method.startsWith('metis_'):
return handleMetisRequest<unknown, TResponse>(method, params, metisEndpoint);

case method === 'ipfs_upload':
return handleIpfsUpload<TResponse>(params as IpfsUploadRequest, ipfsApiKey);

default:
return jsonRpcTransport(...args);
}
};
}

async function handleMetisRequest<TParams, TResponse>(method: string, params: TParams, metisEndpoint?: string): Promise<TResponse> {
const DEFAULT_METIS_ENDPOINT = 'https://public.jupiterapi.com';
const jupiterMethod = method.replace('metis_', '');
const url = new URL(`${metisEndpoint || DEFAULT_METIS_ENDPOINT}/${jupiterMethod}`);
const paramsToUse = Array.isArray(params) ? params[0] : params;

if (typeof paramsToUse === 'object' && paramsToUse !== null) {
Object.entries(paramsToUse as Record<string, unknown>).forEach(([key, value]) => {
url.searchParams.append(key, String(value));
});
}

const response = await fetch(url.toString(), {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
});

if (!response.ok) {
throw new Error(`Error making fetch request to ${url}: ${response.statusText}`);
}

const data = await response.json();
return { result: data } as TResponse;
}


async function handleIpfsUpload<T>(params: IpfsUploadRequest, ipfsApiKey?: string): Promise<T> {
if (!ipfsApiKey) {
throw new Error('No IPFS API key provided');
}

const { filePath, fileName, fileType } = params;
const fileContent = fs.readFileSync(filePath);
const file = new File([fileContent], fileName, { type: fileType });
const formData = new FormData();
formData.append("Body", file);
formData.append("Key", file.name);
formData.append("ContentType", file.type);

const url = new URL('https://api.quicknode.com/ipfs/rest/v1/s3/put-object');
const response = await fetch(url, {
method: 'POST',
headers: {
'x-api-key': ipfsApiKey,
},
body: formData,
redirect: "follow",
});

if (!response.ok) {
throw new Error(`Error making fetch request to ${url}: ${response.statusText}`);
}
const data = await response.json();


return { result: data } as T;
}

interface CreateAddonsApiParams {
endpoint: string;
metisEndpoint?: string;
ipfsApiKey?: string;
}

/**
* Creates an RPC instance with QuickNode Addons API
*
* @param {CreateAddonsApiParams} params - Configuration parameters for creating the API
* @param {string} params.endpoint - Solana HTTP Endpoint. Establish connection to Solana cluster.
* Change as needed to the network you're using.
* Get a free Devnet or Mainnet endpoint from:
* https://www.quicknode.com/signup?utm_source=internal&utm_campaign=sample-apps&utm_content=solana-web3.js-2.0-add-ons
* @param {string} [params.metisEndpoint] - Optional. Endpoint for Metis services if required. (defaults to 'https://public.jupiterapi.com')
* More information at:
* https://marketplace.quicknode.com/add-on/metis-jupiter-v6-swap-api?utm_source=internal&utm_campaign=sample-apps&utm_content=solana-web3.js-2.0-add-ons
* @param {string} [params.ipfsApiKey] - Optional. API key for IPFS services if required.
* More information at:
* hthttps://quicknode.com/ipfs?utm_source=internal&utm_campaign=sample-apps&utm_content=solana-web3.js-2.0-add-ons
* @returns {Rpc<QuickNodeAddons>} RPC instance with QuickNode Addons API
*/


export function createAddonsApi(params: CreateAddonsApiParams): Rpc<QuickNodeAddons> {
const api = createRpcApi<QuickNodeAddons>({
parametersTransformer: (params: unknown[]) => params[0],
responseTransformer: (response: any) => response.result,
});

const transport = createQuickNodeTransport(params);

return createRpc({ api, transport });
}

async function main() {
const quickNodeRpc = createAddonsApi({
endpoint: 'https://replace-me.solana-mainnet.quiknode.pro/123456/',
ipfsApiKey: 'QN_REPLACE_WITH_YOUR_IPFS_API_KEY',
});

try {
const priorityFees = await quickNodeRpc.qn_estimatePriorityFees({
account: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
last_n_blocks: 100
}).send();
console.log(`Priority Fees (Med Per CU): ${priorityFees.per_compute_unit.medium}`);
} catch (error) {
console.error('Error estimating priority fees:', error);
}

try {
const metisQuote = await quickNodeRpc.metis_quote({
inputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
outputMint: "So11111111111111111111111111111111111111112",
amount: 10.03 * 1e6,
}).send();
console.log(`Metis Quote (lamports): ${metisQuote.outAmount}`);
} catch (error) {
console.error('Error getting Metis quote:', error);
}

try {
const result = await quickNodeRpc.ipfs_upload({
filePath: 'test.png',
fileName: 'test5.png',
fileType: 'image/png',
}).send();
console.log('File uploaded successfully! CID:', result.pin.cid);
} catch (error) {
console.error('Error uploading file:', error);
}
}

main().catch(console.error);
127 changes: 127 additions & 0 deletions solana/web3.js-2.0/quicknode-addons/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/* -- PRIORITY FEES API -- */

interface FeeEstimates {
extreme: number;
high: number;
low: number;
medium: number;
percentiles: {
[key: string]: number;
};
}

interface EstimatePriorityFeesResponse {
context: {
slot: number;
};
per_compute_unit: FeeEstimates;
per_transaction: FeeEstimates;
};

interface EstimatePriorityFeesParams {
last_n_blocks?: number;
account?: string;
}

/* -- METIS API -- */

declare const QuoteGetSwapModeEnum: {
readonly ExactIn: "ExactIn";
readonly ExactOut: "ExactOut";
};
type QuoteGetSwapModeEnum = typeof QuoteGetSwapModeEnum[keyof typeof QuoteGetSwapModeEnum];

declare const SwapMode: {
readonly ExactIn: "ExactIn";
readonly ExactOut: "ExactOut";
};
type SwapMode = typeof SwapMode[keyof typeof SwapMode];

interface QuoteGetRequest {
inputMint: string;
outputMint: string;
amount: number;
slippageBps?: number;
swapMode?: QuoteGetSwapModeEnum;
dexes?: Array<string>;
excludeDexes?: Array<string>;
restrictIntermediateTokens?: boolean;
onlyDirectRoutes?: boolean;
asLegacyTransaction?: boolean;
platformFeeBps?: number;
maxAccounts?: number;
}

interface PlatformFee {
amount?: string;
feeBps?: number;
}

interface RoutePlanStep {
swapInfo: SwapInfo;
percent: number;
}

interface SwapInfo {
ammKey: string;
label?: string;
inputMint: string;
outputMint: string;
inAmount: string;
outAmount: string;
feeAmount: string;
feeMint: string;
}

interface QuoteResponse {
inputMint: string;
inAmount: string;
outputMint: string;
outAmount: string;
otherAmountThreshold: string;
swapMode: SwapMode;
slippageBps: number;
platformFee?: PlatformFee;
priceImpactPct: string;
routePlan: Array<RoutePlanStep>;
contextSlot?: number;
timeTaken?: number;
}

/* -- IPFS API -- */

interface IpfsUploadRequest {
filePath: string;
fileName: string;
fileType: string;
}

interface Pin {
cid: string;
name: string;
origins: string[];
meta: Record<string, any>;
}

interface Info {
size: string;
}

interface IpfsUploadResponse {
requestid: string;
status: string;
created: string;
pin: Pin;
info: Info;
delegates: string[];
}

export type {
FeeEstimates,
EstimatePriorityFeesResponse,
EstimatePriorityFeesParams,
QuoteGetRequest,
QuoteResponse,
IpfsUploadRequest,
IpfsUploadResponse
};

0 comments on commit 73bd778

Please sign in to comment.