-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/feat/add-backend' into feat/add-…
…backend-utils
- Loading branch information
Showing
14 changed files
with
421 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
{ | ||
"parser": "@typescript-eslint/parser", | ||
"parserOptions": { | ||
"ecmaVersion": 2020, | ||
"sourceType": "script" | ||
}, | ||
"plugins": ["@typescript-eslint"], | ||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], | ||
"rules": { | ||
"no-undef": "off" | ||
} | ||
"parser": "@typescript-eslint/parser", | ||
"parserOptions": { | ||
"ecmaVersion": 2020, | ||
"sourceType": "script" | ||
}, | ||
"plugins": ["@typescript-eslint"], | ||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], | ||
"rules": { | ||
"no-undef": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
{ | ||
"tabWidth": 2, | ||
"trailingComma": "all", | ||
"arrowParens": "avoid", | ||
"printWidth": 140 | ||
"semi": false, | ||
"singleQuote": true, | ||
"trailingComma": "none" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
export default { | ||
discord: { | ||
baseUrl: () => process.env.DISCORD_URL ?? "https://discord.com", | ||
baseUrl: () => process.env.DISCORD_URL ?? 'https://discord.com' | ||
}, | ||
aws: { | ||
region: process.env.AWS_REGION ?? "us-east-2", | ||
}, | ||
}; | ||
region: process.env.AWS_REGION ?? 'us-east-2' | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,107 @@ | ||
import { Keypair, PublicKey } from "@solana/web3.js"; | ||
import { getSecret } from "../utils/secrets"; | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda"; | ||
import { isAccessTokenValid, signDiscordDigest } from "../utils/discord"; | ||
import { Keypair, PublicKey } from '@solana/web3.js' | ||
import { getSecret } from '../utils/secrets' | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' | ||
import { isAccessTokenValid, signDiscordDigest } from '../utils/discord' | ||
|
||
export interface DiscordSignedDigestRequest { | ||
publicKey: string; | ||
discordId: string; | ||
publicKey: string | ||
discordId: string | ||
} | ||
|
||
export const signDiscordMessage = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { | ||
export const signDiscordMessage = async ( | ||
event: APIGatewayProxyEvent | ||
): Promise<APIGatewayProxyResult> => { | ||
try { | ||
// TODO: no need to receive disordId really, as we should can just get it using the auth token. | ||
// TODO: publicKey was expected as query param in pyth version | ||
const { publicKey, discordId } = JSON.parse(event.body!) as DiscordSignedDigestRequest; | ||
const accessToken = event.headers["x-auth-token"]; | ||
const { publicKey, discordId } = JSON.parse( | ||
event.body! | ||
) as DiscordSignedDigestRequest | ||
const accessToken = event.headers['x-auth-token'] | ||
|
||
validatePublicKey(publicKey); | ||
validateAccessTokenAndDiscordId(accessToken, discordId); | ||
validatePublicKey(publicKey) | ||
validateAccessTokenAndDiscordId(accessToken, discordId) | ||
|
||
await isAccessTokenValid(discordId, accessToken!); | ||
await isAccessTokenValid(discordId, accessToken!) | ||
|
||
const claimant = new PublicKey(publicKey!); | ||
const dispenserGuard = await loadDispenserGuard(); | ||
const claimant = new PublicKey(publicKey!) | ||
const dispenserGuard = await loadDispenserGuard() | ||
|
||
const signedDigest = signDiscordDigest(discordId, claimant, dispenserGuard); | ||
const signedDigest = signDiscordDigest(discordId, claimant, dispenserGuard) | ||
|
||
return { | ||
statusCode: 200, | ||
body: JSON.stringify({ | ||
signature: Buffer.from(signedDigest.signature).toString("hex"), | ||
publicKey: Buffer.from(signedDigest.publicKey).toString("hex"), // The dispenser guard's public key | ||
fullMessage: Buffer.from(signedDigest.fullMessage).toString("hex"), | ||
}), | ||
}; | ||
signature: Buffer.from(signedDigest.signature).toString('hex'), | ||
publicKey: Buffer.from(signedDigest.publicKey).toString('hex'), // The dispenser guard's public key | ||
fullMessage: Buffer.from(signedDigest.fullMessage).toString('hex') | ||
}) | ||
} | ||
} catch (err) { | ||
console.error("Error generating signed discord digest", err); | ||
console.error('Error generating signed discord digest', err) | ||
return { | ||
statusCode: 500, | ||
body: JSON.stringify({ error: "Error generating signed discord digest" }), | ||
}; | ||
body: JSON.stringify({ error: 'Internal server error' }) | ||
} | ||
} | ||
}; | ||
} | ||
|
||
async function loadDispenserGuard() { | ||
// TODO: Update secret name based on the secret you created in the AWS Secrets Manager | ||
const secretData = await getSecret(process.env.DISPENSER_KEY_SECRET_NAME ?? "xli-test-secret-dispenser-guard"); | ||
const dispenserGuardKey = secretData.target; | ||
const secretData = await getSecret( | ||
process.env.DISPENSER_KEY_SECRET_NAME ?? 'xl-dispenser-guard-key' | ||
) | ||
const dispenserGuardKey = secretData.key | ||
|
||
const dispenserGuard = Keypair.fromSecretKey(Uint8Array.from(dispenserGuardKey)); | ||
const dispenserGuard = Keypair.fromSecretKey( | ||
Uint8Array.from(dispenserGuardKey) | ||
) | ||
|
||
return dispenserGuard; | ||
return dispenserGuard | ||
} | ||
|
||
function validatePublicKey(publicKey?: string) { | ||
if (!publicKey) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
error: "Must provide the 'publicKey' query parameter", | ||
}), | ||
}; | ||
error: "Must provide the 'publicKey' query parameter" | ||
}) | ||
} | ||
} | ||
|
||
if (typeof publicKey !== "string") { | ||
if (typeof publicKey !== 'string') { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }), | ||
}; | ||
body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }) | ||
} | ||
} | ||
|
||
try { | ||
new PublicKey(publicKey); | ||
new PublicKey(publicKey) | ||
} catch { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }), | ||
}; | ||
body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }) | ||
} | ||
} | ||
} | ||
|
||
function validateAccessTokenAndDiscordId(AccessToken?: string, discordId?: string) { | ||
function validateAccessTokenAndDiscordId( | ||
AccessToken?: string, | ||
discordId?: string | ||
) { | ||
if (!AccessToken) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ error: "Must provide discord auth token" }), | ||
}; | ||
body: JSON.stringify({ error: 'Must provide discord auth token' }) | ||
} | ||
} | ||
|
||
if (!discordId) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ error: "Must provide discord id" }), | ||
}; | ||
body: JSON.stringify({ error: 'Must provide discord id' }) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' | ||
import { getSecret } from '../utils/secrets' | ||
import { | ||
checkTransactions, | ||
deserializeTransactions | ||
} from '../utils/fundTransactions' | ||
import { Keypair } from '@solana/web3.js' | ||
|
||
interface FundTransactionRequest { | ||
transactions: unknown | ||
} | ||
|
||
export const fundTransaction = async ( | ||
event: APIGatewayProxyEvent | ||
): Promise<APIGatewayProxyResult> => { | ||
try { | ||
const requestBody = JSON.parse(event.body!) as FundTransactionRequest | ||
validateFundTransactions(requestBody.transactions) | ||
const transactions = deserializeTransactions(requestBody.transactions) | ||
const isTransactionsValid = await checkTransactions(transactions) | ||
|
||
if (!isTransactionsValid) { | ||
return { | ||
statusCode: 403, | ||
body: JSON.stringify({ error: 'Unauthorized transactions' }) | ||
} | ||
} | ||
|
||
const wallet = await loadFunderWallet() | ||
|
||
const signedTransactions = await wallet.signAllTransactions(transactions) | ||
return { | ||
statusCode: 200, | ||
body: JSON.stringify({ | ||
signedTransactions: signedTransactions.map((tx) => tx.serialize()) | ||
}) | ||
} | ||
} catch (err) { | ||
console.error('Error fully signing transactions', err) | ||
return { | ||
statusCode: 500, | ||
body: JSON.stringify({ error: 'Internal server error' }) | ||
} | ||
} | ||
} | ||
|
||
function validateFundTransactions(transactions: unknown) { | ||
if (!Array.isArray(transactions) || transactions.length === 0) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ error: 'Must provide transactions' }) | ||
} | ||
} | ||
|
||
if (transactions.length >= 10) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ error: 'Too many transactions' }) | ||
} | ||
} | ||
} | ||
|
||
async function loadFunderWallet(): Promise<NodeWallet> { | ||
const secretData = await getSecret( | ||
process.env.FUNDER_WALLET_KEY_SECRET_NAME ?? 'xli-test-secret-funder-wallet' | ||
) | ||
const funderWalletKey = secretData.key | ||
|
||
const keypair = Keypair.fromSecretKey(new Uint8Array(funderWalletKey)) | ||
|
||
return new NodeWallet(keypair) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
import { getSecret } from "../utils/secrets"; | ||
import { getSecret } from '../utils/secrets' | ||
|
||
export const handler = async () => { | ||
if (!process.env.SECRET_NAME) { | ||
return { | ||
statusCode: 500, | ||
body: JSON.stringify({ error: "SECRET_NAME is not set" }), | ||
}; | ||
body: JSON.stringify({ error: 'SECRET_NAME is not set' }) | ||
} | ||
} | ||
|
||
const secretData = await getSecret(process.env.SECRET_NAME!); | ||
const target = secretData.target; | ||
const secretData = await getSecret(process.env.SECRET_NAME!) | ||
const target = secretData.target | ||
|
||
console.log(`Hello ${target}`); | ||
console.log(`Hello ${target}`) | ||
return { | ||
statusCode: 200, | ||
body: JSON.stringify({ message: `Hello ${target}` }), | ||
}; | ||
}; | ||
body: JSON.stringify({ message: `Hello ${target}` }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import { signDiscordMessage } from "./handlers/discord-signed-digest"; | ||
import { handler as helloworld } from "./handlers/helloworld"; | ||
import { signDiscordMessage } from './handlers/discord-signed-digest' | ||
import { fundTransaction } from './handlers/fund-transactions' | ||
import { handler as helloworld } from './handlers/helloworld' | ||
|
||
export const signDiscordMessageHandler = signDiscordMessage; | ||
export const fundTransactionHandler = helloworld; | ||
export const signDiscordMessageHandler = signDiscordMessage | ||
export const helloworldHandler = helloworld | ||
export const fundTransactionHandler = fundTransaction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
export type SignedMessage = { | ||
publicKey: Uint8Array; | ||
signature: Uint8Array; | ||
publicKey: Uint8Array | ||
signature: Uint8Array | ||
// recoveryId is undefined for ed25519 | ||
recoveryId: number | undefined; | ||
fullMessage: Uint8Array; | ||
}; | ||
recoveryId: number | undefined | ||
fullMessage: Uint8Array | ||
} |
Oops, something went wrong.