Skip to content

Added Poller with Transaction Status #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
95 changes: 91 additions & 4 deletions apps/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import express from "express"
import { authMiddleware } from "./middleware";
import { prismaClient } from "db/client";
import {Prisma} from "db/client";
import cors from "cors";
import { Transaction, SystemProgram, Connection } from "@solana/web3.js";

import { Transaction, SystemProgram, Connection, Keypair, PublicKey, sendAndConfirmTransaction } from "@solana/web3.js";
const privateKey=process.env.PRIVATE_KEY;

const connection = new Connection("https://api.mainnet-beta.solana.com");
const app = express();
Expand Down Expand Up @@ -42,7 +43,9 @@ app.get("/api/v1/website/status", authMiddleware, async (req, res) => {
}
})

res.json(data)
res.json({
data
});

})

Expand Down Expand Up @@ -84,7 +87,91 @@ app.delete("/api/v1/website/", authMiddleware, async (req, res) => {
})

app.post("/api/v1/payout/:validatorId", async (req, res) => {

const validatorId=req.params.validatorId;

const txn=await prismaClient.$transaction(async (prisma)=>{
const validator=await prisma.validator.findUnique({
where:{
id: validatorId
},
select:{
id: true,
pendingPayouts: true,
publicKey: true,
lockedAt: true
}
})

if (!validator){
res.status(404).json({
message: "Validator not found"
});
return;
}

if (validator.lockedAt){
res.json({
message: "Payout is still in process"
});
return;
}

if (validator.pendingPayouts===0){
res.json({
message: "No payout left"
});
return;
}

await prisma.validator.update({
where:{
id: validatorId
},
data:{
lockedAt: new Date()
}
});
return validator;
});
if (!txn) return;

try{
const fromKeypair=Keypair.fromSecretKey(Uint8Array.from(JSON.parse(privateKey!)));
const toPublicKey= new PublicKey(txn.publicKey);
const amount=txn.pendingPayouts * 1000000;

const transaction=new Transaction().add(
SystemProgram.transfer({
fromPubkey: fromKeypair.publicKey,
toPubkey: toPublicKey,
lamports: amount
})
);

const signature=await sendAndConfirmTransaction(connection, transaction, [fromKeypair]);
await prismaClient.validator.update({
where:{id: validatorId},
data:{
lockedAt: null,
transactions:{
create:{
amount: amount,
signature: signature
} as Prisma.TransactionsCreateWithoutValidatorInput
}
}
});

res.json({
message: "Payout Successful with signature: ", signature
})
}catch(e){
console.log("Error processing payout", e);
res.status(500).json({
messsage: "Error processing payout"
});
}

})

app.listen(8080);
25 changes: 15 additions & 10 deletions apps/api/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@ import { JWT_PUBLIC_KEY } from "./config";
export function authMiddleware(req: Request, res: Response, next: NextFunction) {
const token = req.headers['authorization'];
if (!token) {
return res.status(401).json({ error: 'Unauthorized' });
res.status(401).json({ error: 'Unauthorized' });
return;
}

const decoded = jwt.verify(token, JWT_PUBLIC_KEY);
console.log(decoded);
if (!decoded || !decoded.sub) {
return res.status(401).json({ error: 'Unauthorized' });
try{
const decoded = jwt.verify(token, JWT_PUBLIC_KEY);
console.log(decoded);
if (!decoded || !decoded.sub) {
res.status(401).json({ error: 'Unauthorized' });
return;
}
req.userId = decoded.sub as string;
next();
}catch(e){
res.status(401).json({
error: 'Invalid Token'
})
}

req.userId = decoded.sub as string;

next()
}
1 change: 0 additions & 1 deletion apps/api/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

declare namespace Express {
interface Request {
userId?: string
Expand Down
3 changes: 3 additions & 0 deletions apps/frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

# clerk configuration (can include secrets)
/.clerk/
34 changes: 34 additions & 0 deletions apps/poller/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# dependencies (bun install)
node_modules

# output
out
dist
*.tgz

# code coverage
coverage
*.lcov

# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# caches
.eslintcache
.cache
*.tsbuildinfo

# IntelliJ based IDEs
.idea

# Finder (MacOS) folder config
.DS_Store
15 changes: 15 additions & 0 deletions apps/poller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# poller

To install dependencies:

```bash
bun install
```

To run:

```bash
bun run index.ts
```

This project was created using `bun init` in bun v1.2.5. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
1 change: 1 addition & 0 deletions apps/poller/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("Hello via Bun!");
16 changes: 16 additions & 0 deletions apps/poller/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "poller",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest",
"db": "*"
},
"peerDependencies": {
"typescript": "^5"
},
"dependencies": {
"@solana/web3.js": "^1.98.0"
}
}
85 changes: 85 additions & 0 deletions apps/poller/src/poller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Connection, Keypair, PublicKey, sendAndConfirmTransaction, SystemProgram, Transaction } from "@solana/web3.js";
import {prismaClient} from "db/client";

const connection= new Connection(`${process.env.RPC_URL}`);
const maxRetries=3;
const pollingInterval=5000;

const pollPendingTransactions=async()=>{
const pendingTxns= await prismaClient.transactions.findMany({
where:{status: {
in:["Pending", "Failure"]
}}
});

for (const txn of pendingTxns){
try{
const txnStatus=await connection.getSignatureStatus(txn.signature);
if(txnStatus.value?.confirmationStatus==="finalized"){
await prismaClient.$transaction([
prismaClient.transactions.update({
where:{id: txn.id},
data:{
status: "Success"
}
}),
prismaClient.validator.update({
where:{id: txn.id},
data:{
isPaidOut: true,
pendingPayouts: 0
}
})
]);
}else if(txnStatus.value?.err){
if (txn.retryCount>=maxRetries){
console.log(`Transaction ${txn.id} exceeded retry limit`);
break;
}
else {
console.log(`Retrying transaction ${txn.id} attemp no. ${txn.retryCount+1}`);
const fromKeypair=Keypair.fromSecretKey(Uint8Array.from(JSON.parse(`${process.env.PRIVATE_KEY}`)));
const validator= await prismaClient.validator.findMany({
where: {
id: txn.validatorId
}
});
const toPublicKey= new PublicKey(validator.publicKey);
const amount= txn.amount;

const transaction= new Transaction().add(
SystemProgram.transfer({
fromPubkey: fromKeypair.publicKey,
toPubkey: toPublicKey,
lamports: amount
})
)
const newSignature= await sendAndConfirmTransaction(connection, transaction, [fromKeypair]);
await prismaClient.transactions.update({
where:{id: txn.id},
data:{
status: "Pending",
signature: newSignature,
retryCount: {increment: 1}
}
})
}
}else{
await prismaClient.transactions.update({
where:{id: txn.id},
data:{
status: "Failure"
}
});
}
}catch(e){
console.log(`Error checking the txn with id${txn.id}`, e);
}
}

};

const poll=()=>{
setInterval(pollPendingTransactions, pollingInterval);
};
poll();
28 changes: 28 additions & 0 deletions apps/poller/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["esnext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,

// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,

// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,

// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}
4 changes: 1 addition & 3 deletions apps/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,4 @@ async function signMessage(message: string, keypair: Keypair) {

main();

setInterval(async () => {

}, 10000);
setInterval(async () => {}, 10000);
Loading