Use infisical for secrets
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"dockerfilePath": "./src/Managing.Web3Proxy/Dockerfile-web3proxy",
|
||||
"preDeployFunction": "function(captainAppObj, dockerUpdateObject) {\n try {\n console.log('preDeployFunction executing...');\n \n // Ensure TaskTemplate exists\n if (!dockerUpdateObject.TaskTemplate) {\n dockerUpdateObject.TaskTemplate = {};\n }\n \n // Ensure ContainerSpec exists\n if (!dockerUpdateObject.TaskTemplate.ContainerSpec) {\n dockerUpdateObject.TaskTemplate.ContainerSpec = {};\n }\n \n // Initialize Secrets array if it doesn't exist\n if (!dockerUpdateObject.TaskTemplate.ContainerSpec.Secrets) {\n dockerUpdateObject.TaskTemplate.ContainerSpec.Secrets = [];\n }\n \n // Add secrets configuration\n dockerUpdateObject.TaskTemplate.ContainerSpec.Secrets = [\n {\n File: {\n Name: 'PRIVY_APP_ID',\n UID: '0',\n GID: '0',\n Mode: 292\n },\n SecretID: '0r43i7pryk5d2fu0q9vyf46km',\n SecretName: 'privy_app_id'\n },\n {\n File: {\n Name: 'PRIVY_APP_SECRET',\n UID: '0',\n GID: '0',\n Mode: 292\n },\n SecretID: '0z6mjh58drzcrhk2kfbzt1f14',\n SecretName: 'privy_app_secret'\n },\n {\n File: {\n Name: 'PRIVY_AUTHORIZATION_KEY',\n UID: '0',\n GID: '0',\n Mode: 292\n },\n SecretID: 'ieg5bklu1t0otxrp69j4pekvj',\n SecretName: 'privy_auth_key'\n }\n ];\n \n console.log('Secrets configured:', dockerUpdateObject.TaskTemplate.ContainerSpec.Secrets.length, 'secrets');\n \n return Promise.resolve();\n } catch (error) {\n console.error('Error in preDeployFunction:', error);\n throw error;\n }\n}"
|
||||
"dockerfilePath": "./src/Managing.Web3Proxy/Dockerfile-web3proxy"
|
||||
}
|
||||
|
||||
1968
src/Managing.Web3Proxy/package-lock.json
generated
1968
src/Managing.Web3Proxy/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,7 @@
|
||||
"@fastify/swagger-ui": "^5.0.1",
|
||||
"@fastify/type-provider-typebox": "^5.0.0",
|
||||
"@fastify/under-pressure": "^9.0.1",
|
||||
"@infisical/sdk": "^4.0.6",
|
||||
"@privy-io/server-auth": "^1.18.12",
|
||||
"@sentry/node": "^8.55.0",
|
||||
"@sinclair/typebox": "^0.34.11",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fp from 'fastify-plugin'
|
||||
import fs from 'fs'
|
||||
import {InfisicalSDK} from '@infisical/sdk'
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
@@ -11,101 +12,91 @@ declare module 'fastify' {
|
||||
}
|
||||
}
|
||||
|
||||
// Docker secrets are mounted at /run/secrets/ by default in CapRover
|
||||
const readSecretFile = (secretName: string, logger?: any): string | undefined => {
|
||||
const secretPath = `/run/secrets/${secretName}`
|
||||
logger?.debug({ secretPath, exists: fs.existsSync(secretPath) }, `Checking secret file: ${secretName}`)
|
||||
|
||||
if (fs.existsSync(secretPath)) {
|
||||
try {
|
||||
const content = fs.readFileSync(secretPath, 'utf8').trim()
|
||||
logger?.info({ secretName, path: secretPath, length: content.length }, `Successfully read secret: ${secretName}`)
|
||||
return content
|
||||
} catch (error) {
|
||||
logger?.error({ error, secretPath }, `Failed to read secret file ${secretPath}`)
|
||||
return undefined
|
||||
}
|
||||
} else {
|
||||
logger?.warn({ secretPath }, `Secret file does not exist: ${secretPath}`)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads Privy secrets from Infisical in production, or from env vars/files in non-production
|
||||
*/
|
||||
export default fp(async function (fastify) {
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
|
||||
fastify.log.info({ isProd, nodeEnv: process.env.NODE_ENV }, 'Loading Privy secrets')
|
||||
|
||||
// Debug: List all files in /run/secrets/ directory
|
||||
const secretsDir = '/run/secrets'
|
||||
let availableFiles: string[] = []
|
||||
if (fs.existsSync(secretsDir)) {
|
||||
try {
|
||||
availableFiles = fs.readdirSync(secretsDir)
|
||||
fastify.log.info({ files: availableFiles, dir: secretsDir, count: availableFiles.length }, 'Files found in /run/secrets/')
|
||||
|
||||
// Also log full paths and their sizes
|
||||
availableFiles.forEach(file => {
|
||||
const fullPath = `${secretsDir}/${file}`
|
||||
try {
|
||||
const stats = fs.statSync(fullPath)
|
||||
fastify.log.debug({ file, path: fullPath, size: stats.size, isFile: stats.isFile() }, `Secret file details: ${file}`)
|
||||
} catch (err) {
|
||||
fastify.log.warn({ file, path: fullPath, error: err }, `Could not stat secret file: ${file}`)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
fastify.log.warn({ error }, 'Could not list /run/secrets/ directory')
|
||||
}
|
||||
} else {
|
||||
fastify.log.error({ dir: secretsDir }, '/run/secrets/ directory does not exist - Docker secrets may not be mounted')
|
||||
}
|
||||
|
||||
let appId: string
|
||||
let appSecret: string
|
||||
let authKey: string
|
||||
let appId: string = ''
|
||||
let appSecret: string = ''
|
||||
let authKey: string = ''
|
||||
|
||||
if (isProd) {
|
||||
// In production, read from Docker secrets (mounted files)
|
||||
// Try exact names first
|
||||
appId = readSecretFile('PRIVY_APP_ID', fastify.log) || process.env.PRIVY_APP_ID || ''
|
||||
appSecret = readSecretFile('PRIVY_APP_SECRET', fastify.log) || process.env.PRIVY_APP_SECRET || ''
|
||||
authKey = readSecretFile('PRIVY_AUTHORIZATION_KEY', fastify.log) || process.env.PRIVY_AUTHORIZATION_KEY || ''
|
||||
// In production, use Infisical SDK
|
||||
try {
|
||||
const infisicalSiteUrl = process.env.INFISICAL_SITE_URL || 'https://app.infisical.com'
|
||||
const infisicalClientId = process.env.INFISICAL_CLIENT_ID
|
||||
const infisicalClientSecret = process.env.INFISICAL_CLIENT_SECRET
|
||||
const infisicalProjectId = process.env.INFISICAL_PROJECT_ID
|
||||
const infisicalEnvironment = process.env.INFISICAL_ENVIRONMENT || 'prod'
|
||||
|
||||
// If not found, try alternative names (maybe they're mounted with SecretName instead of File.Name)
|
||||
if (!appId && availableFiles.length > 0) {
|
||||
const appIdFile = availableFiles.find(f => f.toLowerCase().includes('app_id') || f.toLowerCase().includes('appid'))
|
||||
if (appIdFile) {
|
||||
fastify.log.info({ foundFile: appIdFile, trying: 'PRIVY_APP_ID' }, 'Trying alternative file name for PRIVY_APP_ID')
|
||||
appId = readSecretFile(appIdFile, fastify.log) || ''
|
||||
}
|
||||
if (!infisicalClientId || !infisicalClientSecret || !infisicalProjectId) {
|
||||
throw new Error('Infisical credentials missing: INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET, and INFISICAL_PROJECT_ID are required in production')
|
||||
}
|
||||
|
||||
if (!appSecret && availableFiles.length > 0) {
|
||||
const appSecretFile = availableFiles.find(f => f.toLowerCase().includes('app_secret') || f.toLowerCase().includes('appsecret'))
|
||||
if (appSecretFile) {
|
||||
fastify.log.info({ foundFile: appSecretFile, trying: 'PRIVY_APP_SECRET' }, 'Trying alternative file name for PRIVY_APP_SECRET')
|
||||
appSecret = readSecretFile(appSecretFile, fastify.log) || ''
|
||||
}
|
||||
}
|
||||
fastify.log.info({
|
||||
siteUrl: infisicalSiteUrl,
|
||||
projectId: infisicalProjectId,
|
||||
environment: infisicalEnvironment
|
||||
}, 'Initializing Infisical SDK')
|
||||
|
||||
if (!authKey && availableFiles.length > 0) {
|
||||
const authKeyFile = availableFiles.find(f => f.toLowerCase().includes('auth_key') || f.toLowerCase().includes('authkey') || f.toLowerCase().includes('authorization'))
|
||||
if (authKeyFile) {
|
||||
fastify.log.info({ foundFile: authKeyFile, trying: 'PRIVY_AUTHORIZATION_KEY' }, 'Trying alternative file name for PRIVY_AUTHORIZATION_KEY')
|
||||
authKey = readSecretFile(authKeyFile, fastify.log) || ''
|
||||
}
|
||||
}
|
||||
const client = new InfisicalSDK({
|
||||
siteUrl: infisicalSiteUrl
|
||||
})
|
||||
|
||||
// Authenticate with Infisical
|
||||
await client.auth().universalAuth.login({
|
||||
clientId: infisicalClientId,
|
||||
clientSecret: infisicalClientSecret
|
||||
})
|
||||
|
||||
fastify.log.info('Authenticated with Infisical successfully')
|
||||
|
||||
// Fetch all secrets for the project
|
||||
const allSecrets = await client.secrets().listSecrets({
|
||||
environment: infisicalEnvironment,
|
||||
projectId: infisicalProjectId,
|
||||
viewSecretValue: true
|
||||
})
|
||||
|
||||
fastify.log.info({
|
||||
secretCount: allSecrets.secrets?.length || 0
|
||||
}, 'Fetched secrets from Infisical')
|
||||
|
||||
// Extract Privy secrets
|
||||
const privyAppIdSecret = allSecrets.secrets?.find(s => s.secretKey === 'PRIVY_APP_ID')
|
||||
const privyAppSecretSecret = allSecrets.secrets?.find(s => s.secretKey === 'PRIVY_APP_SECRET')
|
||||
const privyAuthKeySecret = allSecrets.secrets?.find(s => s.secretKey === 'PRIVY_AUTHORIZATION_KEY')
|
||||
|
||||
appId = privyAppIdSecret?.secretValue || process.env.PRIVY_APP_ID || ''
|
||||
appSecret = privyAppSecretSecret?.secretValue || process.env.PRIVY_APP_SECRET || ''
|
||||
authKey = privyAuthKeySecret?.secretValue || process.env.PRIVY_AUTHORIZATION_KEY || ''
|
||||
|
||||
fastify.log.info({
|
||||
appId: !!appId,
|
||||
appSecret: !!appSecret,
|
||||
authKey: !!authKey,
|
||||
appIdLength: appId.length,
|
||||
appSecretLength: appSecret.length,
|
||||
authKeyLength: authKey.length,
|
||||
availableSecretFiles: availableFiles
|
||||
}, 'Privy secrets loaded from Docker secrets')
|
||||
appIdFound: !!privyAppIdSecret,
|
||||
appSecretFound: !!privyAppSecretSecret,
|
||||
authKeyFound: !!privyAuthKeySecret
|
||||
}, 'Privy secrets loaded from Infisical')
|
||||
|
||||
} catch (error) {
|
||||
fastify.log.error({
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined
|
||||
}, 'Failed to load secrets from Infisical')
|
||||
|
||||
// Fallback to environment variables
|
||||
appId = process.env.PRIVY_APP_ID || ''
|
||||
appSecret = process.env.PRIVY_APP_SECRET || ''
|
||||
authKey = process.env.PRIVY_AUTHORIZATION_KEY || ''
|
||||
|
||||
fastify.log.warn('Falling back to environment variables for Privy secrets')
|
||||
}
|
||||
} else {
|
||||
// In non-production, use env vars or file paths
|
||||
const readMaybeFile = (envKey: string, fileKey: string): string | undefined => {
|
||||
@@ -127,9 +118,7 @@ export default fp(async function (fastify) {
|
||||
appSecret: !!appSecret,
|
||||
authKey: !!authKey,
|
||||
isProd,
|
||||
nodeEnv: process.env.NODE_ENV,
|
||||
availableSecretFiles: availableFiles,
|
||||
secretsDirExists: fs.existsSync(secretsDir)
|
||||
nodeEnv: process.env.NODE_ENV
|
||||
}, '⚠️ WARNING: Privy secrets not fully resolved at plugin load - app will continue but Privy operations will fail')
|
||||
|
||||
// Still decorate with empty strings so the app doesn't crash
|
||||
@@ -142,11 +131,15 @@ export default fp(async function (fastify) {
|
||||
|
||||
fastify.log.error({
|
||||
message: 'Please check:',
|
||||
checks: [
|
||||
'1. Docker secrets are created: docker secret ls',
|
||||
'2. preDeployFunction in captain-definition is executing',
|
||||
'3. Secret IDs in captain-definition match actual secret IDs',
|
||||
'4. Container has access to /run/secrets/ directory'
|
||||
checks: isProd ? [
|
||||
'1. INFISICAL_CLIENT_ID environment variable is set',
|
||||
'2. INFISICAL_CLIENT_SECRET environment variable is set',
|
||||
'3. INFISICAL_PROJECT_ID environment variable is set',
|
||||
'4. Secrets exist in Infisical with keys: PRIVY_APP_ID, PRIVY_APP_SECRET, PRIVY_AUTHORIZATION_KEY',
|
||||
'5. Machine Identity has access to the project and environment'
|
||||
] : [
|
||||
'1. Environment variables PRIVY_APP_ID, PRIVY_APP_SECRET, PRIVY_AUTHORIZATION_KEY are set',
|
||||
'2. Or file paths are set via PRIVY_APP_ID_FILE, PRIVY_APP_SECRET_FILE, PRIVY_AUTHORIZATION_KEY_FILE'
|
||||
]
|
||||
}, 'Debugging steps for missing secrets')
|
||||
|
||||
|
||||
@@ -51,53 +51,20 @@ declare module 'fastify' {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a secret from Docker secrets mount point (production only)
|
||||
*/
|
||||
const readDockerSecret = (secretName: string): string | undefined => {
|
||||
if (process.env.NODE_ENV !== 'production') return undefined
|
||||
|
||||
const secretPath = `/run/secrets/${secretName}`
|
||||
if (fs.existsSync(secretPath)) {
|
||||
try {
|
||||
return fs.readFileSync(secretPath, 'utf8').trim()
|
||||
} catch (error) {
|
||||
console.error(`Failed to read Docker secret ${secretPath}:`, error)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an initialized PrivyClient instance with configuration from environment variables
|
||||
* Returns an initialized PrivyClient instance with configuration from secrets
|
||||
* @returns The configured PrivyClient instance
|
||||
*/
|
||||
export const getPrivyClient = (fastify?: FastifyInstance): PrivyClient => {
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
|
||||
// Try multiple sources in order of preference:
|
||||
// 1. Fastify decorator (populated by privy-secrets plugin)
|
||||
// 1. Fastify decorator (populated by privy-secrets plugin - Infisical in prod, env in dev)
|
||||
// 2. Fastify config (from env plugin)
|
||||
// 3. Docker secrets (production only)
|
||||
// 4. Environment variables
|
||||
// 3. Environment variables (fallback)
|
||||
|
||||
const decorated = (fastify as any)?.privySecrets as { appId: string; appSecret: string; authKey: string } | undefined
|
||||
|
||||
let appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID
|
||||
let appSecret = decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET
|
||||
let authKey = decorated?.authKey || fastify?.config?.PRIVY_AUTHORIZATION_KEY
|
||||
|
||||
// In production, fall back to Docker secrets if not found in decorator/config
|
||||
if (isProd) {
|
||||
if (!appId) appId = readDockerSecret('PRIVY_APP_ID')
|
||||
if (!appSecret) appSecret = readDockerSecret('PRIVY_APP_SECRET')
|
||||
if (!authKey) authKey = readDockerSecret('PRIVY_AUTHORIZATION_KEY')
|
||||
}
|
||||
|
||||
// Final fallback to environment variables
|
||||
appId = appId || process.env.PRIVY_APP_ID
|
||||
appSecret = appSecret || process.env.PRIVY_APP_SECRET
|
||||
authKey = authKey || process.env.PRIVY_AUTHORIZATION_KEY
|
||||
const appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID
|
||||
const appSecret = decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET || process.env.PRIVY_APP_SECRET
|
||||
const authKey = decorated?.authKey || fastify?.config?.PRIVY_AUTHORIZATION_KEY || process.env.PRIVY_AUTHORIZATION_KEY
|
||||
|
||||
if (!appId || !appSecret || !authKey) {
|
||||
console.warn('Missing Privy environment variables:');
|
||||
@@ -108,18 +75,9 @@ export const getPrivyClient = (fastify?: FastifyInstance): PrivyClient => {
|
||||
console.warn('Fastify privySecrets decorated:', !!decorated);
|
||||
console.warn('Fastify config available:', !!fastify?.config);
|
||||
|
||||
// In production, also log Docker secret file existence
|
||||
if (isProd) {
|
||||
console.warn('Docker secrets check:');
|
||||
console.warn(' /run/secrets/PRIVY_APP_ID exists:', fs.existsSync('/run/secrets/PRIVY_APP_ID'));
|
||||
console.warn(' /run/secrets/PRIVY_APP_SECRET exists:', fs.existsSync('/run/secrets/PRIVY_APP_SECRET'));
|
||||
console.warn(' /run/secrets/PRIVY_AUTHORIZATION_KEY exists:', fs.existsSync('/run/secrets/PRIVY_AUTHORIZATION_KEY'));
|
||||
}
|
||||
|
||||
throw new Error('Missing required Privy environment variables');
|
||||
}
|
||||
|
||||
console.log('appId', appId);
|
||||
console.log('Privy client initialized successfully');
|
||||
|
||||
return new PrivyClient(
|
||||
@@ -137,16 +95,24 @@ export const getPrivyClient = (fastify?: FastifyInstance): PrivyClient => {
|
||||
* Authentication function for Privy API calls
|
||||
* @param url The URL for the API endpoint
|
||||
* @param body The request body
|
||||
* @param fastify Optional Fastify instance to get secrets from decorator
|
||||
* @returns The authorization signature
|
||||
*/
|
||||
export async function getAuthorizationSignature({url, body}: {url: string; body: object}) {
|
||||
export async function getAuthorizationSignature(
|
||||
{url, body}: {url: string; body: object},
|
||||
fastify?: FastifyInstance
|
||||
) {
|
||||
// Get app ID from Fastify decorator or env
|
||||
const decorated = (fastify as any)?.privySecrets as { appId: string; authKey: string } | undefined
|
||||
const appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID || ''
|
||||
|
||||
const payload = {
|
||||
version: 1,
|
||||
method: 'POST',
|
||||
url,
|
||||
body,
|
||||
headers: {
|
||||
'privy-app-id': process.env.PRIVY_APP_ID || ''
|
||||
'privy-app-id': appId
|
||||
}
|
||||
};
|
||||
|
||||
@@ -155,18 +121,16 @@ export async function getAuthorizationSignature({url, body}: {url: string; body:
|
||||
const serializedPayload = canonicalize(payload) as string;
|
||||
const serializedPayloadBuffer = Buffer.from(serializedPayload);
|
||||
|
||||
// Resolve authorization key: Docker secrets in production, file/env in non-production
|
||||
// Resolve authorization key: from Fastify decorator (Infisical in prod), file/env in non-production
|
||||
let resolvedKey: string | undefined
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// In production, read from Docker secrets mounted at /run/secrets/
|
||||
const secretPath = '/run/secrets/PRIVY_AUTHORIZATION_KEY'
|
||||
if (fs.existsSync(secretPath)) {
|
||||
resolvedKey = fs.readFileSync(secretPath, 'utf8').trim()
|
||||
|
||||
// Try Fastify decorator first (loaded from Infisical in production)
|
||||
if (decorated?.authKey) {
|
||||
resolvedKey = decorated.authKey
|
||||
} else if (fastify?.config?.PRIVY_AUTHORIZATION_KEY) {
|
||||
resolvedKey = fastify.config.PRIVY_AUTHORIZATION_KEY
|
||||
} else {
|
||||
resolvedKey = process.env.PRIVY_AUTHORIZATION_KEY
|
||||
}
|
||||
} else {
|
||||
// Non-production: allow file fallback
|
||||
// Fallback to file or env var
|
||||
const filePath = process.env.PRIVY_AUTHORIZATION_KEY_FILE
|
||||
const fromFile = filePath && fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8').trim() : undefined
|
||||
resolvedKey = fromFile || process.env.PRIVY_AUTHORIZATION_KEY || undefined
|
||||
@@ -200,24 +164,16 @@ export const makePrivyRequest = async <T>(
|
||||
url: string,
|
||||
body: object = {},
|
||||
requiresAuth = true,
|
||||
method: 'GET' | 'POST' = 'POST'
|
||||
method: 'GET' | 'POST' = 'POST',
|
||||
fastify?: FastifyInstance
|
||||
): Promise<T> => {
|
||||
try {
|
||||
// Resolve secrets: Docker secrets in production, env in non-production
|
||||
let appId: string
|
||||
let appSecret: string
|
||||
// Resolve secrets: from Fastify decorator (Infisical in prod), env in non-production
|
||||
const decorated = (fastify as any)?.privySecrets as { appId: string; appSecret: string } | undefined
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// In production, read from Docker secrets mounted at /run/secrets/
|
||||
const appIdPath = '/run/secrets/PRIVY_APP_ID'
|
||||
const appSecretPath = '/run/secrets/PRIVY_APP_SECRET'
|
||||
appId = (fs.existsSync(appIdPath) ? fs.readFileSync(appIdPath, 'utf8').trim() : undefined) || process.env.PRIVY_APP_ID || ''
|
||||
appSecret = (fs.existsSync(appSecretPath) ? fs.readFileSync(appSecretPath, 'utf8').trim() : undefined) || process.env.PRIVY_APP_SECRET || ''
|
||||
} else {
|
||||
// Non-production: use env vars
|
||||
appId = process.env.PRIVY_APP_ID || ''
|
||||
appSecret = process.env.PRIVY_APP_SECRET || ''
|
||||
}
|
||||
// Try Fastify decorator first (loaded from Infisical in production)
|
||||
const appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID || ''
|
||||
const appSecret = decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET || process.env.PRIVY_APP_SECRET || ''
|
||||
|
||||
let headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -1023,11 +979,12 @@ export const sendTokenImpl = async (
|
||||
export const getWalletBalanceImpl = async (
|
||||
address: string,
|
||||
assets: Ticker[],
|
||||
chains: string[]
|
||||
chains: string[],
|
||||
fastify?: FastifyInstance
|
||||
): Promise<Balance[]> => {
|
||||
try {
|
||||
// First, get the user by wallet address using Privy Client
|
||||
const privy = getPrivyClient();
|
||||
const privy = getPrivyClient(fastify);
|
||||
|
||||
// Get user by wallet address
|
||||
const user = await privy.getUserByWalletAddress(address);
|
||||
@@ -1085,7 +1042,7 @@ export const getWalletBalanceImpl = async (
|
||||
usd: string;
|
||||
};
|
||||
}>;
|
||||
}>(balanceUrl, {}, true, 'GET');
|
||||
}>(balanceUrl, {}, true, 'GET', fastify);
|
||||
|
||||
// Convert to Balance interface format (matching ManagingApiTypes.ts)
|
||||
const balances: Balance[] = balanceResponse.balances
|
||||
@@ -1211,8 +1168,8 @@ export async function getWalletBalance(
|
||||
throw new Error('At least one chain is required for balance retrieval');
|
||||
}
|
||||
|
||||
// Call the getWalletBalanceImpl function
|
||||
const balances = await getWalletBalanceImpl(address, assets, chains);
|
||||
// Call the getWalletBalanceImpl function, passing the Fastify instance from the request
|
||||
const balances = await getWalletBalanceImpl(address, assets, chains, this.server);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -86,7 +86,7 @@ export const autoConfig = {
|
||||
* @see {@link https://github.com/fastify/fastify-env}
|
||||
*/
|
||||
export default fp(async (fastify) => {
|
||||
// In production, Privy secrets come from Docker secrets (mounted files), not env vars
|
||||
// In production, Privy secrets come from Infisical, not env vars
|
||||
// Make them optional in the schema to avoid validation errors
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
const required = isProd
|
||||
|
||||
Reference in New Issue
Block a user