-
Notifications
You must be signed in to change notification settings - Fork 22
/
transaction.ts
142 lines (122 loc) · 3.58 KB
/
transaction.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { Cluster, clusterApiUrl, Connection, PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL, Keypair } from '@solana/web3.js'
import type { NextApiRequest, NextApiResponse } from 'next'
type GetResponse = {
label: string,
icon: string,
};
export type PostRequest = {
account: string,
};
export type PostResponse = {
transaction: string,
message: string,
network: Cluster,
};
export type PostError = {
error: string
};
// Response for GET request
function get(res: NextApiResponse<GetResponse>) {
res.status(200).json({
label: 'My Store',
icon: 'https://solanapay.com/src/img/branding/Solanapay.com/downloads/gradient.svg',
});
}
// Main body of the POST request, this returns the transaction
async function postImpl(
network: Cluster,
account: PublicKey,
reference: PublicKey
): Promise<PostResponse> {
// Can also use a custom RPC here
const endpoint = clusterApiUrl(network);
const connection = new Connection(endpoint);
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
// Create any transaction
const transaction = new Transaction({
feePayer: account,
blockhash,
lastValidBlockHeight,
});
const transferInstruction = SystemProgram.transfer({
fromPubkey: account,
toPubkey: Keypair.generate().publicKey,
lamports: LAMPORTS_PER_SOL / 1000,
});
// Add reference as a key to the instruction
// This allows us to listen for this transaction
transferInstruction.keys.push({
pubkey: reference,
isSigner: false,
isWritable: false,
});
transaction.add(transferInstruction);
// Serialize the transaction and convert to base64 to return it
const serializedTransaction = transaction.serialize({
requireAllSignatures: false // account is a missing signature
});
const base64 = serializedTransaction.toString('base64');
// Return the serialized transaction
return {
transaction: base64,
message: 'Thankyou for your purchase!',
network,
};
}
// We pass eg. network in query params, this function extracts the value of a query param
function getFromQuery(
req: NextApiRequest,
field: string
): string | undefined {
if (!(field in req.query)) return undefined;
const value = req.query[field];
if (typeof value === 'string') return value;
// value is string[]
if (value.length === 0) return undefined;
return value[0];
}
async function post(
req: NextApiRequest,
res: NextApiResponse<PostResponse | PostError>
) {
const { account } = req.body as PostRequest
console.log(req.body)
if (!account) {
res.status(400).json({ error: 'No account provided' })
return
}
const network = getFromQuery(req, 'network') as Cluster;
if (!network) {
res.status(400).json({ error: 'No network provided' });
return
}
const reference = getFromQuery(req, 'reference');
if (!reference) {
res.status(400).json({ error: 'No reference provided' })
return
}
try {
const postResponse = await postImpl(
network,
new PublicKey(account),
new PublicKey(reference),
);
res.status(200).json(postResponse)
} catch (error) {
console.error(error)
res.status(500).json({ error: 'Error creating transaction' })
}
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<GetResponse | PostResponse | PostError>
) {
if (req.method === 'GET') {
return get(res);
} else if (req.method === 'POST') {
return await post(req, res);
} else {
return res.status(405).json({ error: 'Method not allowed' });
}
}