本文介绍了如何使用 Shyft 的 gRPC 服务来流式传输 Moonshot 上的交易数据。 Moonshot 简化了 Solana 上的 meme 币的发行和发现,Shyft 使得通过 gRPC 服务流式传输交易和获取交易信息成为可能。文章详细介绍了如何设置 gRPC 连接、订阅交易流、以及实时处理和反序列化数据,通过示例代码展示了整个过程。
Moonshot 简化了 Solana 区块链上 meme 币的启动和发现,类似于 pump. fun. 它提供了一个平台,交易者可以在早期投资有前途的 meme 代币,从而有可能获得巨额利润。由于启动的代币数量不断增加,早期投资项目可能具有挑战性,这使得监控它们变得困难。虽然 Moonshot 相对较新,几乎没有可用于流式传输数据的开发工具,但 Shyft 可以使用 gRPC 服务流式传输交易并获取在 Moonshot 上进行交易的必要信息。本教程将探讨如何使用 gRPC 在 Moonshot 上流式传输交易,并有可能获得巨额利润。
要开始使用,我们需要准备一些东西。
身份验证:你的 Shyft API 密钥、gRPC 端点和 gRPC Token
你可以从 Shyft 网站 获取你自己的 Shyft API 密钥(Shyft 使用的身份验证参数)。你还可以在 Shyft 仪表板 上找到你所在地区的 gRPC 端点和访问Token。
用于接收 gRPC 数据的服务器端后端(如 NodeJS)
由于 Web 浏览器不支持 gRPC 服务,因此你需要一个后端应用程序来接收 gRPC 数据。 在本例中,我们使用了 NodeJS,但也可以使用任何其他后端服务器端语言,如 C#、Go、Java、Kotlin、Python 或 PHP。
在本文中,我们将研究如何使用 gRPC 在 Moonshot 上流式传输“交易”。我们将涵盖以下主题,
首先,我们需要克隆可以找到代码的 git 存储库。
要使用 Git 克隆存储库,请执行以下过程:
git clone
,后跟要克隆的存储库的 URL。它看起来应该像这样$ git clone <https://github.com/Shyft-to/solana-defi.git>
在你的终端上,你需要使用 cd grpc-moonshot
打开代码所在的文件夹,并使用 npm install
安装所有依赖项。
cd grpc-moonshot
npm install
与本文相关的所有代码都可以在我们的 GitHub 上找到 。请随时克隆它并继续学习。
要开始使用 gRPC 从 Moonshot 流式传输数据,我们需要建立客户端服务。 这需要两个关键信息: gRPC URL 和 gRPC 访问Token。 访问Token是一种安全凭证,通常是一长串字母数字字符,而 URL 是你的 gRPC 区域 URL。 掌握了这两个详细信息后,我们就可以继续设置客户端服务并开始从 Moonshot 流式传输数据
const client = new Client(
'你的特定区域的 Shyft gRPC URL',
'Shyft gRPC 访问Token',
undefined,
);
现在我们可以继续从区块链获取我们的数据。
我们的目标是使用 gRPC 从 Solana 区块链流式传输特定数据。为实现此目的,我们将利用
client: Client
:此参数用于订阅链上事件并建立与 Solana 区块链的连接。
arg: SubscriberRequest
:此参数指定我们要从区块链获取的数据。
使用 handleStream()
函数,我们可以高效便捷地在 Solana 区块链上流式传输实时链上数据
interface SubscribeRequest {
accounts: { [key: string]: SubscribeRequestFilterAccounts };
slots: { [key: string]: SubscribeRequestFilterSlots };
transactions: { [key: string]: SubscribeRequestFilterTransactions };
transactionsStatus: { [key: string]: SubscribeRequestFilterTransactions };
blocks: { [key: string]: SubscribeRequestFilterBlocks };
blocksMeta: { [key: string]: SubscribeRequestFilterBlocksMeta };
entry: { [key: string]: SubscribeRequestFilterEntry };
commitment?: CommitmentLevel | undefined;
accountsDataSlice: SubscribeRequestAccountsDataSlice[];
ping?: SubscribeRequestPing | undefined;
}
async function handleStream(client: Client, args: SubscribeRequest) {
// 订阅事件
const stream = await client.subscribe();
// 创建 `error` / `end` 处理程序
const streamClosed = new Promise<void>((resolve, reject) => {
stream.on("error", (error) => {
console.log("ERROR", error);
reject(error);
stream.end();
});
stream.on("end", () => {
resolve();
});
stream.on("close", () => {
resolve();
});
});
// 处理更新
stream.on("data", async (data) => {
try{
console.log(data);
}catch(error){
if(error){
console.log(error)
}
}
});
// 发送订阅请求
await new Promise<void>((resolve, reject) => {
stream.write(args, (err: any) => {
if (err === null || err === undefined) {
resolve();
} else {
reject(err);
}
});
}).catch((reason) => {
console.error(reason);
throw reason;
});
await streamClosed;
}
要从 Solana 区块链上的 Moonshot 获取代币交易,我们需要定义一个 SubscriberRequest
对象,该对象指定我们的数据请求的参数。 此对象应包括以下信息:
以下是用于获取 Moonshot 上的代币交易的 SubscriberRequest
对象的示例:
const req = {
accounts: {},
slots: {},
transactions: {
moonshot: {
vote: false,
failed: false,
signature: undefined,
accountInclude: ['MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG'], //Address MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG
accountExclude: [],
accountRequired: [],
},
},
transactionsStatus: {},
entry: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
ping: undefined,
commitment: CommitmentLevel.CONFIRMED, //用于接收已确认的 txn 更新
};
字符串 'MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG'
代表 Solana 区块链上 Moonshot 的链上地址。 要流式传输此地址的实时链上数据,我们需要定义 SubscribeCommand
函数。 此函数将用于指定我们的数据请求的参数,并建立与 Solana 区块链的流式传输端点的连接。 SubscribeCommand
函数应接受一个 SubscriberRequest
对象作为其参数,并使用它来订阅 Solana 区块链上所需的的数据流。
async function subscribeCommand(client: Client, args: SubscribeRequest) {
while (true) {
try {
await handleStream(client, args);
} catch (error) {
console.error("Stream error, restarting in 1 second...", error);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
}
并调用它
subscribeCommand(client, req);
我们的输出应该如下所示
{
filters: [ 'moonshot' ],
account: undefined,
slot: undefined,
transaction: {
transaction: {
signature: <Buffer 18 f2 41 ca 0d c3 2d 24 a3 4c 25 0b 0f d5 e0 bd fd 75 35 a1 ed a3 43 8a f8 fc 86 c0 01 08 70 32 f9 ac 53 3c 46 e8 e2 62 22 4c 79 ab 3f f5 4b d5 81 0c ... 14 more bytes>,
isVote: false,
transaction: [Object],
meta: [Object],
index: '315'
},
slot: '283417510'
},
block: undefined,
ping: undefined,
pong: undefined,
blockMeta: undefined,
entry: undefined
}
我们已成功从 Solana 区块链请求数据,但输出格式尚不便于理解。 为了使数据更清晰,我们需要对其进行反序列化。 此过程涉及将原始数据转换为可以被我们的应用程序轻松读取和解释的格式。 数据反序列化后,我们可以访问我们感兴趣的特定信息,并根据需要使用它。
要将从 Solana 区块链的流式传输端点获得的数据转换为更易于理解和使用的格式,我们需要对数据进行反序列化。 以下是如何编写函数来反序列化数据的示例:
import base58 from "bs58";
export function decodeTransact(data){
const output = data?base58.encode(Buffer.from(data,'base64')):"";
return output;
}
该函数将任何缓冲数据解码为更可用的格式。
在反序列化从 Solana 区块链的流式传输端点接收的数据之后,我们可能希望格式化输出,使其更具可读性和可用性。 这可能涉及将数据组织成对象结构,并根据需要添加其他属性或方法
export function tOutPut(data){
const dataTx = data?data?.transaction?.transaction:null;
const signature = decodeTransact(dataTx?.signature);
const message = dataTx?.transaction?.message
const header = message?.header;
const accountKeys = message?.accountKeys.map((t)=>{
return decodeTransact(t)
})
const recentBlockhash = decodeTransact(message?.recentBlockhash);
const instructions = message?.instructions
const meta = dataTx?.meta
return {
signature,
message:{
header,
accountKeys,
recentBlockhash,
instructions
},
meta
}
}
我们重新编码 handleStream()
函数以适应更新的代码
async function handleStream(client: Client, args: SubscribeRequest) {
// 订阅事件
const stream = await client.subscribe();
// 创建 `error` / `end` 处理程序
const streamClosed = new Promise<void>((resolve, reject) => {
stream.on("error", (error) => {
console.log("ERROR", error);
reject(error);
stream.end();
});
stream.on("end", () => {
resolve();
});
stream.on("close", () => {
resolve();
});
});
// 处理更新
stream.on("data", async (data) => {
try{
const result = await tOutPut(data);
console.log(result.signature !==''?result:'');
}catch(error){
if(error){
console.log(error)
}
}
});
// 发送订阅请求
await new Promise<void>((resolve, reject) => {
stream.write(args, (err: any) => {
if (err === null || err === undefined) {
resolve();
} else {
reject(err);
}
});
}).catch((reason) => {
console.error(reason);
throw reason;
});
await streamClosed;
}
最后,我们使用 SubscribeCommand
函数进行调用
subscribeCommand(client, req);
输出应该如下所示
{
signature: 'F3ase8GKiytLqoMiPBL4sptPuuaYPW3fpwGJ6r7dV2uxmogHC6TFbQdzyvVb77YXgxvtCwuYv38UFSqXAsCsMFJ',
message: {
header: {
numRequiredSignatures: 1,
numReadonlySignedAccounts: 0,
numReadonlyUnsignedAccounts: 7
},
accountKeys: [\
'97g5tRgnKM7d7EZf2W9o3NxGMPksXJoLDTUAycocAQuK',\
'4QkvjiH6sHvTCJXsZiXamCC2ysP1bfVfdtVC9ja5hfaE',\
'mvVnB62M7aUsNppDVA9betcTqir9te2YzVEjNXjyghX',\
'CQYpAhWmJFSCPgZJBYVN3mV4VKr37X2geU3nTewsYbeW',\
'3udvfL24waJcLhskRAsStNMoNUvtyXdxrWQz4hgi953N',\
'5K5RtTWzzLp4P8Npi84ocf7F1vBsAu29N1irG4iiUnzt',\
'ComputeBudget111111111111111111111111111111',\
'MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG',\
'BLnMt8KrxBtG1mXAjSgba2Nuodj3kCVzbQYFSP4bybHN',\
'36Eru7v11oU5Pfrojyn5oY3nETA1a1iqsw2WUu6afkM9',\
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL',\
'11111111111111111111111111111111'\
],
recentBlockhash: 'ABwgGgy713Z6czNDJFQSK2ubiCeTAz8pDCn57KgnpPrP',
instructions: [ [Object], [Object] ]
},
meta: {
err: undefined,
fee: '25000',
preBalances: [\
'344615897', '2039280',\
'9963175231', '2039280',\
'8323215952497', '259293084532',\
'1', '1141440',\
'1461600', '3695760',\
'934087680', '731913600',\
'1'\
],
postBalances: [\
'346044889', '2039280',\
'9961706553', '2039280',\
'8323215964245', '259293087470',\
'1', '1141440',\
'1461600', '3695760',\
'934087680', '731913600',\
'1'\
],
innerInstructions: [ [Object] ],
innerInstructionsNone: false,
logMessages: [\
'Program ComputeBudget111111111111111111111111111111 invoke [1]',\
'Program ComputeBudget111111111111111111111111111111 success',\
'Program MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG invoke [1]',\
'Program log: Instruction: Sell',\
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]',\
'Program log: Instruction: TransferChecked',\
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6147 of 171847 compute units',\
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success',\
'Program log: Transfering collateral from buyer to curve account: 1468678, Helio fee: 2938, Dex fee: 11748',\
'Program data: vdt/007mYe7zz7Pm7RoAAAZpFgAAAAAA5C0AAAAAAAB6CwAAAAAAAJEtbwURArYDC4ILPxD2CUa4FmMaMw96vJcSUCkj1DuqK4dqcsjMXQoGm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAXiTLEfL8KvuPTDg6RVaqQbRyn4zxend6hy0mdI4TxcuAQUAAAB0cmFkZQ==',\
'Program MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG consumed 37734 of 199850 compute units',\
'Program MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG success'\
],
logMessagesNone: false,
preTokenBalances: [ [Object], [Object] ],
postTokenBalances: [ [Object], [Object] ],
rewards: [],
loadedWritableAddresses: [],
loadedReadonlyAddresses: [],
returnData: undefined,
returnDataNone: true,
computeUnitsConsumed: '37884'
}
}
{
signature: '5YqVBBkFggF3ciFjahP8T5Q2NaGHtp5qHkxPnjBGZePqgvDQRzLPNQ9ayi1W5d7n1wmo6LfnqB5FsyjaDjZrMwk3',
message: {
header: {
numRequiredSignatures: 1,
numReadonlySignedAccounts: 0,
numReadonlyUnsignedAccounts: 7
},
accountKeys: [\
'6kXJBci9Qbfn2rwWKxMYLYHBEGxayaRULn8chKwNrZFC',\
'2ePzHUn5hXotG3i78tGg3fkSPmKAeC5GHy12zTaPw8a1',\
'FTkdej4H2Gp4YhLZWkyzLzH2dNzKdLMryodqRrhHtaY9',\
'GgDyDkmpMsr3AkPZ6rbJRHiUtXRpXC8Jg8eAD1ft3Cwb',\
'3udvfL24waJcLhskRAsStNMoNUvtyXdxrWQz4hgi953N',\
'5K5RtTWzzLp4P8Npi84ocf7F1vBsAu29N1irG4iiUnzt',\
'ComputeBudget111111111111111111111111111111',\
'MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG',\
'FMV1DqEWrS8VBiPB8qiQYfgyxQwJQqn2HYv1hiwUR3e9',\
'36Eru7v11oU5Pfrojyn5oY3nETA1a1iqsw2WUu6afkM9',\
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL',\
'11111111111111111111111111111111'\
],
recentBlockhash: 'S6pLqsRmTNxiynMHUzcEBL6bQcNFumKibxn2h4UM76q',
instructions: [ [Object], [Object] ]
},
meta: {
err: undefined,
fee: '6600',
preBalances: [\
'44012931', '2039280',\
'13550876129', '2039280',\
'8323215964245', '259293087470',\
'1', '1141440',\
'1461600', '3695760',\
'934087680', '731913600',\
'1'\
],
postBalances: [\
'9868250', '2039280',\
'13584676210', '2039280',\
'8323216234645', '259293155070',\
'1', '1141440',\
'1461600', '3695760',\
'934087680', '731913600',\
'1'\
],
innerInstructions: [ [Object] ],
innerInstructionsNone: false,
logMessages: [\
'Program ComputeBudget111111111111111111111111111111 invoke [1]',\
'Program ComputeBudget111111111111111111111111111111 success',\
'Program MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG invoke [1]',\
'Program log: Instruction: Buy',\
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]',\
'Program log: Instruction: TransferChecked',\
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6147 of 165113 compute units',\
'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success',\
'Program 11111111111111111111111111111111 invoke [2]',\
'Program 11111111111111111111111111111111 success',\
'Program 11111111111111111111111111111111 invoke [2]',\
'Program 11111111111111111111111111111111 success',\
'Program 11111111111111111111111111111111 invoke [2]',\
'Program 11111111111111111111111111111111 success',\
'Program log: Transfering collateral from buyer to curve account: 33800081, Helio fee: 67600, Dex fee: 270400',\
'Program data: vdt/007mYe4AmkbpKpIAAJG/AwIAAAAAQCAEAAAAAAAQCAEAAAAAADkLCdQS3JkB1t4NgWtwaSxbggMUEpqXZ5M4amSlpe5mL9DR/cKY7uoGm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAVVwql70RJfaHQQqopGcce9nko4PrwdIvkPwzmAU4nTvAAUAAAB0cmFkZQ==',\
'Program MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG consumed 50139 of 199850 compute units',\
'Program MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG success'\
],
logMessagesNone: false,
preTokenBalances: [ [Object], [Object] ],
postTokenBalances: [ [Object], [Object] ],
rewards: [],
loadedWritableAddresses: [],
loadedReadonlyAddresses: [],
returnData: undefined,
returnDataNone: true,
computeUnitsConsumed: '50289'
}
}
在 Shyft,我们很高兴推出一种用于在 Solana 区块链上流式传输数据的创新解决方案:gRPC。 这项技术简化了链上数据的流式传输,使开发人员可以专注于构建强大的应用程序,从而利用 Solana 区块链的强大功能。 借助 gRPC,开发人员可以享受更简单的代码库和更低的延迟。 使用专用节点在 Solana 区块链上流式传输数据可能很复杂且资源密集,需要更大、更复杂的代码库。 但是,借助 gRPC,此过程得到了简化,从而更容易构建即使是最复杂的项目。 我们致力于提供必要的工具和支持,以使此过程无缝衔接。 总之,gRPC 为在 Solana 区块链上构建的开发人员提供了以下几个好处:
如需进一步帮助,我们邀请你加入我们的 Discord 服务器 或在 Twitter 上关注我们以获取更新。 我们的团队随时为你提供帮助,充分利用这项创新技术。
与本文相关的所有代码都可以在我们的 GitHub 上找到 。请随时克隆它并继续学习。要了解有关 Solana 上数据流的更多信息,请查看我们关于 在 Solana 上流式传输实时数据 、 使用 gRPC 进行实时数据流:帐户、交易、区块 、 如何在 Solana 上流式传输实时 Pump.fun 更新 或 跟踪 Raydium 上的新池 的文章。
- 原文链接: blogs.shyft.to/how-to-st...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!