Skip to content

Commit cd11014

Browse files
manumanu
authored andcommitted
Lamports not working
1 parent 9c479e5 commit cd11014

File tree

3 files changed

+48
-25
lines changed

3 files changed

+48
-25
lines changed

nodes/webhooks/CrossmintWebhooks.node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export class CrossmintWebhooks implements INodeType {
175175
required: true,
176176
default: 1000000,
177177
description:
178-
'The minimum payment amount required to trigger the workflow. This is in Wei for the token specified. For example, USDC has 6 decimals, so for $1.00 payment enter 1000000.',
178+
'The minimum payment amount required in atomic units (must be an integer). Examples: SOL uses lamports (9 decimals) - 0.006 SOL = 6000000 lamports. USDC uses 6 decimals - $1.00 = 1000000. No decimal points allowed.',
179179
},
180180
],
181181
},

nodes/webhooks/executions/Webhooks.ts

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
import { setupOutputConnection } from '../utils/webhookUtils';
88
// import { rm, } from 'fs/promises';
99
import type * as express from 'express';
10-
import { createPrivateKey, sign as cryptoSign } from 'crypto';
10+
import { createPrivateKey, sign as cryptoSign, randomBytes } from 'crypto';
11+
import { signAsync as ed25519SignAsync } from './crypto/ED25519';
1112

1213
export interface IPaymentPayload {
1314
x402Version: number;
@@ -45,14 +46,8 @@ export interface IPaymentRequirements {
4546

4647

4748
export async function webhookTrigger(this: IWebhookFunctions): Promise<IWebhookResponseData> {
48-
const webhookType = this.getNodeParameter('webhookType') as string;
4949
const body = this.getBodyData();
50-
51-
if (webhookType === 'x402') {
52-
return await handleX402Webhook.call(this, body);
53-
} else {
54-
throw new Error(`Unsupported webhook type: ${webhookType}`);
55-
}
50+
return await handleX402Webhook.call(this, body);
5651
}
5752

5853
async function handleX402Webhook(
@@ -397,36 +392,64 @@ function detectSigningAlg(keyObj: ReturnType<typeof createPrivateKey>): {
397392
throw new Error(`Unsupported key type: ${type}. Use Ed25519 or EC P-256.`);
398393
}
399394

400-
function buildCdpJwt(params: {
395+
async function buildCdpJwtAsync(params: {
401396
apiKeyId: string;
402397
apiKeySecret: string;
403398
method: string;
404399
host: string;
405400
path: string;
406401
expiresInSec?: number;
407-
audience?: string[];
408-
}): string {
409-
const { apiKeyId, apiKeySecret, method, host, path, expiresInSec = 120, audience = ['cdp-api'] } = params;
410-
const keyObj = toKeyObjectFromSecret(apiKeySecret);
411-
const { algHeader, signAlg } = detectSigningAlg(keyObj);
402+
}): Promise<string> {
403+
const { apiKeyId, apiKeySecret, method, host, path, expiresInSec = 120 } = params;
404+
405+
let algHeader: 'EdDSA' | 'ES256';
406+
let signAlg: null | 'sha256' = null;
407+
let keyObj: ReturnType<typeof createPrivateKey> | undefined;
408+
let useEd25519Noble = false;
409+
410+
if (apiKeySecret.startsWith('-----BEGIN')) {
411+
keyObj = toKeyObjectFromSecret(apiKeySecret);
412+
const det = detectSigningAlg(keyObj);
413+
algHeader = det.algHeader;
414+
signAlg = det.signAlg;
415+
} else {
416+
// Sign exactly like our ED25519.ts usage: expect base64-encoded 32-byte Ed25519 secret
417+
useEd25519Noble = true;
418+
algHeader = 'EdDSA';
419+
}
412420

413421
const now = Math.floor(Date.now() / 1000);
414-
const header = { alg: algHeader, typ: 'JWT', kid: apiKeyId } as const;
422+
const header = {
423+
alg: algHeader,
424+
typ: 'JWT',
425+
kid: apiKeyId,
426+
nonce: randomBytes(16).toString('hex'),
427+
} as const;
415428
const payload = {
416-
iss: 'coinbase-cloud',
429+
iss: 'cdp',
417430
sub: apiKeyId,
418-
iat: now,
419431
nbf: now,
420432
exp: now + expiresInSec,
421-
audience: undefined,
422-
aud: audience,
423-
uris: [`${method.toUpperCase()} ${host}${path}`],
433+
uri: `${method.toUpperCase()} ${host}${path}`,
424434
};
425435

426436
const encHeader = base64UrlEncode(JSON.stringify(header));
427437
const encPayload = base64UrlEncode(JSON.stringify(payload));
428438
const signingInput = Buffer.from(`${encHeader}.${encPayload}`);
429-
const signature = cryptoSign(signAlg as any, signingInput, keyObj);
439+
440+
let signature: Buffer;
441+
if (useEd25519Noble) {
442+
// Expect raw 32-byte Ed25519 secret in base64
443+
const raw = Buffer.from(apiKeySecret, 'base64');
444+
if (raw.length !== 32) {
445+
throw new Error('Invalid Ed25519 secret: expected base64-encoded 32-byte key');
446+
}
447+
const sig = await ed25519SignAsync(signingInput, raw);
448+
signature = Buffer.from(sig);
449+
} else {
450+
// Use Node crypto with either Ed25519 (signAlg null) or ES256
451+
signature = cryptoSign(signAlg as any, signingInput, keyObj!);
452+
}
430453
const encSig = base64UrlEncode(signature);
431454
return `${encHeader}.${encPayload}.${encSig}`;
432455
}
@@ -438,7 +461,7 @@ async function verifyX402Payment(
438461
paymentRequirements: PaymentRequirements,
439462
): Promise<{ isValid: boolean; invalidReason?: string }>
440463
{
441-
const token = buildCdpJwt({ apiKeyId, apiKeySecret, method: 'POST', host: CDP_HOST, path: FACILITATOR_VERIFY_PATH });
464+
const token = await buildCdpJwtAsync({ apiKeyId, apiKeySecret, method: 'POST', host: CDP_HOST, path: FACILITATOR_VERIFY_PATH });
442465
const res = await fetch(`https://${CDP_HOST}${FACILITATOR_VERIFY_PATH}`, {
443466
method: 'POST',
444467
headers: {
@@ -462,7 +485,7 @@ async function settleX402Payment(
462485
paymentRequirements: PaymentRequirements,
463486
): Promise<{ success: boolean; txHash?: string; error?: string }>
464487
{
465-
const token = buildCdpJwt({ apiKeyId, apiKeySecret, method: 'POST', host: CDP_HOST, path: FACILITATOR_SETTLE_PATH });
488+
const token = await buildCdpJwtAsync({ apiKeyId, apiKeySecret, method: 'POST', host: CDP_HOST, path: FACILITATOR_SETTLE_PATH });
466489
const res = await fetch(`https://${CDP_HOST}${FACILITATOR_SETTLE_PATH}`, {
467490
method: 'POST',
468491
headers: {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"n8n": {
3131
"n8nNodesApiVersion": 1,
3232
"credentials": [
33-
"dist/credentials/CrossmintApi.credentials.js",
33+
"dist/credentials/CrossmintApi.credentials.js"
3434
],
3535
"nodes": [
3636
"dist/nodes/CrossmintWallets/CrossmintWallets.node.js",

0 commit comments

Comments
 (0)