Skip to content
This repository was archived by the owner on Mar 18, 2026. It is now read-only.
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
38 changes: 20 additions & 18 deletions actions/everstake/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Keypair,
Transaction,
Authorized,
ComputeBudgetProgram
ComputeBudgetProgram,
} from '@solana/web3.js';
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
import {
Expand All @@ -15,12 +15,16 @@ import {
actionsSpecOpenApiPostResponse,
} from '../openapi';
import { prepareTransaction } from '../../shared/transaction-utils';
import { ActionGetResponse, ActionPostRequest, ActionPostResponse } from '@solana/actions';
import {
ActionGetResponse,
ActionPostRequest,
ActionPostResponse,
} from '@solana/actions';
import { connection } from '../../shared/connection';
require('dotenv').config();

const VALIDATOR_ADDRESS = '9QU2QSxhb24FUX3Tu2FpczXjpK3VYrvRudywSZaM29mF';
const VALIDATOR_ADDRESS_DEVNET ='FwR3PbjS5iyqzLiLugrBqKSa5EKZ4vK9SKs7eQXtT59f';
const VALIDATOR_ADDRESS_DEVNET = 'FwR3PbjS5iyqzLiLugrBqKSa5EKZ4vK9SKs7eQXtT59f';
const STAKE_AMOUNT_SOL_OPTIONS = [1, 5, 10];
const DEFAULT_STAKE_AMOUNT_SOL = 1;

Expand All @@ -33,7 +37,7 @@ app.openapi(
tags: ['Stake'],
responses: actionsSpecOpenApiGetResponse,
}),
(c) => {
(c) => {
const requestUrl = new URL(c.req.url);
const { icon, title, description } = getStakeInfo(requestUrl.origin);
const amountParameterName = 'amount';
Expand Down Expand Up @@ -124,8 +128,7 @@ app.openapi(
responses: actionsSpecOpenApiPostResponse,
}),
async (c) => {
const amount =
c.req.param('amount') ?? DEFAULT_STAKE_AMOUNT_SOL.toString();
const amount = c.req.param('amount') ?? DEFAULT_STAKE_AMOUNT_SOL.toString();
const { account } = (await c.req.json()) as ActionPostRequest;

let validator_address = VALIDATOR_ADDRESS;
Expand All @@ -146,14 +149,13 @@ app.openapi(
},
);

function getStakeInfo(baseURL: string): Pick<
ActionGetResponse,
'icon' | 'title' | 'description'
> {
const icon = new URL("/static/Everstake.png", baseURL).toString();
function getStakeInfo(
baseURL: string,
): Pick<ActionGetResponse, 'icon' | 'title' | 'description'> {
const icon = new URL('/static/Everstake.png', baseURL).toString();
const title = 'Stake SOL with Everstake, earn 7% APR';
const description =
"Everstake, the biggest staking provider in the blockchain industry, trusted by 735,000+ users!";
'Everstake, the biggest staking provider in the blockchain industry, trusted by 735,000+ users!';
return { icon, title, description };
}

Expand All @@ -165,12 +167,12 @@ async function prepareStakeTransaction(
const stakeAccount = Keypair.generate();

// Calculate how much we want to stake
const minimumRent = await connection.getMinimumBalanceForRentExemption(
StakeProgram.space,
)
const minimumRent = await connection.getMinimumBalanceForRentExemption(
StakeProgram.space,
);

const tx = new Transaction().add(
ComputeBudgetProgram.setComputeUnitPrice({microLamports: 50}),
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 50 }),
StakeProgram.createAccount({
authorized: new Authorized(sender, sender),
fromPubkey: sender,
Expand All @@ -180,8 +182,8 @@ async function prepareStakeTransaction(
StakeProgram.delegate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: sender,
votePubkey: validatorVoteAccount
})
votePubkey: validatorVoteAccount,
}),
);

let versionedTX = await prepareTransaction(tx.instructions, sender);
Expand Down
101 changes: 49 additions & 52 deletions actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ import { serve } from '@hono/node-server';
import everstake from './everstake/route';
import { cors } from 'hono/cors';
import { swaggerUI } from '@hono/swagger-ui';
import * as path from "node:path";
import { readFileSync } from "node:fs";
import * as path from 'node:path';
import { readFileSync } from 'node:fs';
import { OpenAPIHono, createRoute } from '@hono/zod-openapi';
import { z } from "zod";
var mime = require('mime-types')
import { z } from 'zod';
var mime = require('mime-types');

const app = new OpenAPIHono();

app.use(
'/*',
cors({
origin: '*',
allowHeaders: ['Content-Type', 'Accept-Encoding', 'Authorization'],
allowMethods: ['POST', 'GET', 'OPTIONS'],
exposeHeaders: [],
maxAge: 600,
credentials: true,
})
'/*',
cors({
origin: '*',
allowHeaders: ['Content-Type', 'Accept-Encoding', 'Authorization'],
allowMethods: ['POST', 'GET', 'OPTIONS'],
exposeHeaders: [],
maxAge: 600,
credentials: true,
}),
);

// <--Actions-->
Expand All @@ -41,23 +41,23 @@ app.get(
}),
);

app.get("/actions.json", async (c) => {
app.get('/actions.json', async (c) => {
const [payload, mime_type] = loadFile('actions.json');
return new Response(payload, {
headers: {
"content-type": mime_type,
},
status: 200,
});
return new Response(payload, {
headers: {
'content-type': mime_type,
},
status: 200,
});
});

// Download File
const downloadFileRoute = createRoute({
method: "get",
path: "/static/{file}",
summary: "static files",
tags: ['Static'],
request: {
method: 'get',
path: '/static/{file}',
summary: 'static files',
tags: ['Static'],
request: {
params: z.object({
file: z.string().openapi({
param: {
Expand All @@ -68,42 +68,39 @@ const downloadFileRoute = createRoute({
example: 'file.jpg',
}),
}),
},
responses: {
200: {
content: {
"image/png": {
schema: z.any().openapi({
type: "object",
format: "binary",
}),
}
},
description:
"Return file, contentType can be image/png or image/jpeg",
},
},
},
responses: {
200: {
content: {
'image/png': {
schema: z.any().openapi({
type: 'object',
format: 'binary',
}),
},
},
description: 'Return file, contentType can be image/png or image/jpeg',
},
},
});

// disable ts check because hono openapi cannot validate raw response
// @ts-ignore: Unreachable code error
app.openapi(downloadFileRoute, async (c) => {
const file = c.req.param('file');
const [payload, mime_type] = loadFile(file);
return new Response(payload, {
headers: {
"content-type": mime_type,
},
status: 200,
});
return new Response(payload, {
headers: {
'content-type': mime_type,
},
status: 200,
});
});

function loadFile(
file: string
): [Buffer, string] {
const payload = readFileSync(path.join("./static", file));
const mime_type = mime.lookup(path.join("./static", file));
return [payload, mime_type]
function loadFile(file: string): [Buffer, string] {
const payload = readFileSync(path.join('./static', file));
const mime_type = mime.lookup(path.join('./static', file));
return [payload, mime_type];
}

const port = 3000;
Expand Down