@atxp/solana 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -0
- package/dist/index.cjs +140 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +136 -0
- package/dist/index.js.map +1 -0
- package/dist/solanaAccount.d.ts +13 -0
- package/dist/solanaAccount.d.ts.map +1 -0
- package/dist/solanaAccount.js +34 -0
- package/dist/solanaAccount.js.map +1 -0
- package/dist/solanaPaymentMaker.d.ts +25 -0
- package/dist/solanaPaymentMaker.d.ts.map +1 -0
- package/dist/solanaPaymentMaker.js +108 -0
- package/dist/solanaPaymentMaker.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ATXP Solana
|
|
2
|
+
|
|
3
|
+
ATXP is a framework for building and running agents that can interact with the world. See [docs.atxp.ai](https://docs.atxp.ai) for documentation and examples.
|
|
4
|
+
|
|
5
|
+
ATXP Solana provides Solana blockchain support for `@atxp/client`, enabling payments and authentication using Solana wallets.
|
|
6
|
+
|
|
7
|
+
## Support
|
|
8
|
+
|
|
9
|
+
For detailed API documentation, configuration options, and advanced usage patterns, please refer to our [complete documentation](https://docs.atxp.ai/).
|
|
10
|
+
|
|
11
|
+
Have questions or need help? Join our [Discord community](https://discord.gg/FuJXHhe9aW) - we're happy to help!
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @atxp/solana @solana/web3.js @solana/pay bs58
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { SolanaAccount } from '@atxp/solana';
|
|
23
|
+
import { atxpClient } from '@atxp/client';
|
|
24
|
+
import { Keypair } from '@solana/web3.js';
|
|
25
|
+
|
|
26
|
+
// Create or load a Solana keypair
|
|
27
|
+
const keypair = Keypair.generate();
|
|
28
|
+
|
|
29
|
+
// Create a Solana account
|
|
30
|
+
const account = new SolanaAccount({
|
|
31
|
+
keypair,
|
|
32
|
+
solanaRpcUrl: 'https://api.mainnet-beta.solana.com'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Use with atxpClient
|
|
36
|
+
const client = await atxpClient({
|
|
37
|
+
account,
|
|
38
|
+
mcpServer: 'https://browse.mcp.atxp.ai/'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const res = await client.callTool({
|
|
42
|
+
name: 'atxp_browse',
|
|
43
|
+
arguments: { query: 'What is Solana?' }
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## SolanaAccount
|
|
48
|
+
|
|
49
|
+
The `SolanaAccount` class provides Solana wallet integration for ATXP:
|
|
50
|
+
|
|
51
|
+
- **Authentication**: Signs JWTs using Solana keypair for MCP server authentication
|
|
52
|
+
- **Payments**: Makes USDC payments on Solana using SPL tokens
|
|
53
|
+
- **Wallet Integration**: Works with any Solana wallet that provides a `Keypair`
|
|
54
|
+
|
|
55
|
+
### Configuration
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const account = new SolanaAccount({
|
|
59
|
+
keypair: Keypair, // Your Solana keypair
|
|
60
|
+
solanaRpcUrl: string, // Solana RPC endpoint
|
|
61
|
+
logger?: Logger // Optional logger instance
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## SolanaPaymentMaker
|
|
66
|
+
|
|
67
|
+
The `SolanaPaymentMaker` class handles USDC payments on Solana:
|
|
68
|
+
|
|
69
|
+
- Uses `@solana/pay` for payment transactions
|
|
70
|
+
- Supports USDC SPL token transfers
|
|
71
|
+
- Validates transactions before and after sending
|
|
72
|
+
|
|
73
|
+
You generally don't need to use this directly - `SolanaAccount` uses it internally.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var client = require('@atxp/client');
|
|
4
|
+
var web3_js = require('@solana/web3.js');
|
|
5
|
+
var pay = require('@solana/pay');
|
|
6
|
+
var splToken = require('@solana/spl-token');
|
|
7
|
+
var bs58 = require('bs58');
|
|
8
|
+
var BigNumber = require('bignumber.js');
|
|
9
|
+
var common = require('@atxp/common');
|
|
10
|
+
var jose = require('jose');
|
|
11
|
+
|
|
12
|
+
// this is a global public key for USDC on the solana mainnet
|
|
13
|
+
const USDC_MINT = new web3_js.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
|
14
|
+
const ValidateTransferError = pay.ValidateTransferError;
|
|
15
|
+
class SolanaPaymentMaker {
|
|
16
|
+
constructor(solanaEndpoint, sourceSecretKey, logger) {
|
|
17
|
+
this.generateJWT = async ({ paymentRequestId, codeChallenge, accountId }) => {
|
|
18
|
+
// Solana/Web3.js secretKey is 64 bytes:
|
|
19
|
+
// first 32 bytes are the private scalar, last 32 are the public key.
|
|
20
|
+
// JWK expects only the 32-byte private scalar for 'd'
|
|
21
|
+
const jwk = {
|
|
22
|
+
kty: 'OKP',
|
|
23
|
+
crv: 'Ed25519',
|
|
24
|
+
d: Buffer.from(this.source.secretKey.slice(0, 32)).toString('base64url'),
|
|
25
|
+
x: Buffer.from(this.source.publicKey.toBytes()).toString('base64url'),
|
|
26
|
+
};
|
|
27
|
+
const privateKey = await jose.importJWK(jwk, 'EdDSA');
|
|
28
|
+
if (!(privateKey instanceof CryptoKey)) {
|
|
29
|
+
throw new Error('Expected CryptoKey from importJWK');
|
|
30
|
+
}
|
|
31
|
+
return common.generateJWT(this.source.publicKey.toBase58(), privateKey, paymentRequestId || '', codeChallenge || '', accountId);
|
|
32
|
+
};
|
|
33
|
+
this.makePayment = async (destinations, memo, _paymentRequestId) => {
|
|
34
|
+
// Filter to solana chain destinations
|
|
35
|
+
const solanaDestinations = destinations.filter(d => d.chain === 'solana');
|
|
36
|
+
if (solanaDestinations.length === 0) {
|
|
37
|
+
this.logger.debug('SolanaPaymentMaker: No solana destinations found, cannot handle payment');
|
|
38
|
+
return null; // Cannot handle these destinations
|
|
39
|
+
}
|
|
40
|
+
// Pick first solana destination
|
|
41
|
+
const dest = solanaDestinations[0];
|
|
42
|
+
const amount = dest.amount;
|
|
43
|
+
const currency = dest.currency;
|
|
44
|
+
const receiver = dest.address;
|
|
45
|
+
if (currency.toUpperCase() !== 'USDC') {
|
|
46
|
+
throw new client.PaymentNetworkError('Only USDC currency is supported; received ' + currency);
|
|
47
|
+
}
|
|
48
|
+
const receiverKey = new web3_js.PublicKey(receiver);
|
|
49
|
+
this.logger.info(`Making payment of ${amount} ${currency} to ${receiver} on Solana from ${this.source.publicKey.toBase58()}`);
|
|
50
|
+
try {
|
|
51
|
+
// Check balance before attempting payment
|
|
52
|
+
const tokenAccountAddress = await splToken.getAssociatedTokenAddress(USDC_MINT, this.source.publicKey);
|
|
53
|
+
const tokenAccount = await splToken.getAccount(this.connection, tokenAccountAddress);
|
|
54
|
+
const balance = new BigNumber(tokenAccount.amount.toString()).dividedBy(10 ** 6); // USDC has 6 decimals
|
|
55
|
+
if (balance.lt(amount)) {
|
|
56
|
+
this.logger.warn(`Insufficient ${currency} balance for payment. Required: ${amount}, Available: ${balance}`);
|
|
57
|
+
throw new client.InsufficientFundsError(currency, amount, balance, 'solana');
|
|
58
|
+
}
|
|
59
|
+
// Get the destination token account address (this will be the transactionId)
|
|
60
|
+
const destinationTokenAccount = await splToken.getAssociatedTokenAddress(USDC_MINT, receiverKey);
|
|
61
|
+
// Increase compute units to handle both memo and token transfer
|
|
62
|
+
// Memo uses ~6000 CUs, token transfer needs ~6500 CUs
|
|
63
|
+
const modifyComputeUnits = web3_js.ComputeBudgetProgram.setComputeUnitLimit({
|
|
64
|
+
units: 50000,
|
|
65
|
+
});
|
|
66
|
+
const addPriorityFee = web3_js.ComputeBudgetProgram.setComputeUnitPrice({
|
|
67
|
+
microLamports: 20000,
|
|
68
|
+
});
|
|
69
|
+
const transaction = await pay.createTransfer(this.connection, this.source.publicKey, {
|
|
70
|
+
amount: amount,
|
|
71
|
+
recipient: receiverKey,
|
|
72
|
+
splToken: USDC_MINT,
|
|
73
|
+
memo,
|
|
74
|
+
});
|
|
75
|
+
transaction.add(modifyComputeUnits);
|
|
76
|
+
transaction.add(addPriorityFee);
|
|
77
|
+
const transactionSignature = await web3_js.sendAndConfirmTransaction(this.connection, transaction, [this.source]);
|
|
78
|
+
// Return transaction signature as transactionId and token account address as transactionSubId
|
|
79
|
+
return {
|
|
80
|
+
transactionId: transactionSignature,
|
|
81
|
+
transactionSubId: destinationTokenAccount.toBase58(),
|
|
82
|
+
chain: 'solana',
|
|
83
|
+
currency: 'USDC'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (error instanceof client.InsufficientFundsError || error instanceof client.PaymentNetworkError) {
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
// Wrap other errors in PaymentNetworkError
|
|
91
|
+
throw new client.PaymentNetworkError(`Payment failed on Solana network: ${error.message}`, error);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
if (!solanaEndpoint) {
|
|
95
|
+
throw new Error('Solana endpoint is required');
|
|
96
|
+
}
|
|
97
|
+
if (!sourceSecretKey) {
|
|
98
|
+
throw new Error('Source secret key is required');
|
|
99
|
+
}
|
|
100
|
+
this.connection = new web3_js.Connection(solanaEndpoint, { commitment: 'confirmed' });
|
|
101
|
+
this.source = web3_js.Keypair.fromSecretKey(bs58.decode(sourceSecretKey));
|
|
102
|
+
this.logger = logger ?? new common.ConsoleLogger();
|
|
103
|
+
}
|
|
104
|
+
getSourceAddress(_params) {
|
|
105
|
+
return this.source.publicKey.toBase58();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
class SolanaAccount {
|
|
110
|
+
constructor(solanaEndpoint, sourceSecretKey) {
|
|
111
|
+
if (!solanaEndpoint) {
|
|
112
|
+
throw new Error('Solana endpoint is required');
|
|
113
|
+
}
|
|
114
|
+
if (!sourceSecretKey) {
|
|
115
|
+
throw new Error('Source secret key is required');
|
|
116
|
+
}
|
|
117
|
+
const source = web3_js.Keypair.fromSecretKey(bs58.decode(sourceSecretKey));
|
|
118
|
+
this.sourcePublicKey = source.publicKey.toBase58();
|
|
119
|
+
// Format accountId as network:address
|
|
120
|
+
this.accountId = `solana:${this.sourcePublicKey}`;
|
|
121
|
+
this.paymentMakers = [
|
|
122
|
+
new SolanaPaymentMaker(solanaEndpoint, sourceSecretKey)
|
|
123
|
+
];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get sources for this account
|
|
127
|
+
*/
|
|
128
|
+
async getSources() {
|
|
129
|
+
return [{
|
|
130
|
+
address: this.sourcePublicKey,
|
|
131
|
+
chain: 'solana',
|
|
132
|
+
walletType: 'eoa'
|
|
133
|
+
}];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
exports.SolanaAccount = SolanaAccount;
|
|
138
|
+
exports.SolanaPaymentMaker = SolanaPaymentMaker;
|
|
139
|
+
exports.ValidateTransferError = ValidateTransferError;
|
|
140
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/solanaPaymentMaker.ts","../src/solanaAccount.ts"],"sourcesContent":[null,null],"names":["PublicKey","_ValidateTransferError","importJWK","generateJWT","PaymentNetworkError","getAssociatedTokenAddress","getAccount","InsufficientFundsError","ComputeBudgetProgram","createTransfer","sendAndConfirmTransaction","Connection","Keypair","ConsoleLogger"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Account, PaymentMaker } from '@atxp/client';
|
|
2
|
+
import { AccountId, Source, Logger, Currency, Destination, PaymentIdentifier } from '@atxp/common';
|
|
3
|
+
import { ValidateTransferError as ValidateTransferError$1 } from '@solana/pay';
|
|
4
|
+
import BigNumber from 'bignumber.js';
|
|
5
|
+
|
|
6
|
+
declare class SolanaAccount implements Account {
|
|
7
|
+
accountId: AccountId;
|
|
8
|
+
paymentMakers: PaymentMaker[];
|
|
9
|
+
private sourcePublicKey;
|
|
10
|
+
constructor(solanaEndpoint: string, sourceSecretKey: string);
|
|
11
|
+
/**
|
|
12
|
+
* Get sources for this account
|
|
13
|
+
*/
|
|
14
|
+
getSources(): Promise<Source[]>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare const ValidateTransferError: typeof ValidateTransferError$1;
|
|
18
|
+
declare class SolanaPaymentMaker implements PaymentMaker {
|
|
19
|
+
private connection;
|
|
20
|
+
private source;
|
|
21
|
+
private logger;
|
|
22
|
+
constructor(solanaEndpoint: string, sourceSecretKey: string, logger?: Logger);
|
|
23
|
+
getSourceAddress(_params: {
|
|
24
|
+
amount: BigNumber;
|
|
25
|
+
currency: Currency;
|
|
26
|
+
receiver: string;
|
|
27
|
+
memo: string;
|
|
28
|
+
}): string;
|
|
29
|
+
generateJWT: ({ paymentRequestId, codeChallenge, accountId }: {
|
|
30
|
+
paymentRequestId: string;
|
|
31
|
+
codeChallenge: string;
|
|
32
|
+
accountId?: AccountId | null;
|
|
33
|
+
}) => Promise<string>;
|
|
34
|
+
makePayment: (destinations: Destination[], memo: string, _paymentRequestId?: string) => Promise<PaymentIdentifier | null>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { SolanaAccount, SolanaPaymentMaker, ValidateTransferError };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { PaymentNetworkError, InsufficientFundsError } from '@atxp/client';
|
|
2
|
+
import { PublicKey, ComputeBudgetProgram, sendAndConfirmTransaction, Connection, Keypair } from '@solana/web3.js';
|
|
3
|
+
import { ValidateTransferError as ValidateTransferError$1, createTransfer } from '@solana/pay';
|
|
4
|
+
import { getAssociatedTokenAddress, getAccount } from '@solana/spl-token';
|
|
5
|
+
import bs58 from 'bs58';
|
|
6
|
+
import BigNumber from 'bignumber.js';
|
|
7
|
+
import { generateJWT, ConsoleLogger } from '@atxp/common';
|
|
8
|
+
import { importJWK } from 'jose';
|
|
9
|
+
|
|
10
|
+
// this is a global public key for USDC on the solana mainnet
|
|
11
|
+
const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
|
12
|
+
const ValidateTransferError = ValidateTransferError$1;
|
|
13
|
+
class SolanaPaymentMaker {
|
|
14
|
+
constructor(solanaEndpoint, sourceSecretKey, logger) {
|
|
15
|
+
this.generateJWT = async ({ paymentRequestId, codeChallenge, accountId }) => {
|
|
16
|
+
// Solana/Web3.js secretKey is 64 bytes:
|
|
17
|
+
// first 32 bytes are the private scalar, last 32 are the public key.
|
|
18
|
+
// JWK expects only the 32-byte private scalar for 'd'
|
|
19
|
+
const jwk = {
|
|
20
|
+
kty: 'OKP',
|
|
21
|
+
crv: 'Ed25519',
|
|
22
|
+
d: Buffer.from(this.source.secretKey.slice(0, 32)).toString('base64url'),
|
|
23
|
+
x: Buffer.from(this.source.publicKey.toBytes()).toString('base64url'),
|
|
24
|
+
};
|
|
25
|
+
const privateKey = await importJWK(jwk, 'EdDSA');
|
|
26
|
+
if (!(privateKey instanceof CryptoKey)) {
|
|
27
|
+
throw new Error('Expected CryptoKey from importJWK');
|
|
28
|
+
}
|
|
29
|
+
return generateJWT(this.source.publicKey.toBase58(), privateKey, paymentRequestId || '', codeChallenge || '', accountId);
|
|
30
|
+
};
|
|
31
|
+
this.makePayment = async (destinations, memo, _paymentRequestId) => {
|
|
32
|
+
// Filter to solana chain destinations
|
|
33
|
+
const solanaDestinations = destinations.filter(d => d.chain === 'solana');
|
|
34
|
+
if (solanaDestinations.length === 0) {
|
|
35
|
+
this.logger.debug('SolanaPaymentMaker: No solana destinations found, cannot handle payment');
|
|
36
|
+
return null; // Cannot handle these destinations
|
|
37
|
+
}
|
|
38
|
+
// Pick first solana destination
|
|
39
|
+
const dest = solanaDestinations[0];
|
|
40
|
+
const amount = dest.amount;
|
|
41
|
+
const currency = dest.currency;
|
|
42
|
+
const receiver = dest.address;
|
|
43
|
+
if (currency.toUpperCase() !== 'USDC') {
|
|
44
|
+
throw new PaymentNetworkError('Only USDC currency is supported; received ' + currency);
|
|
45
|
+
}
|
|
46
|
+
const receiverKey = new PublicKey(receiver);
|
|
47
|
+
this.logger.info(`Making payment of ${amount} ${currency} to ${receiver} on Solana from ${this.source.publicKey.toBase58()}`);
|
|
48
|
+
try {
|
|
49
|
+
// Check balance before attempting payment
|
|
50
|
+
const tokenAccountAddress = await getAssociatedTokenAddress(USDC_MINT, this.source.publicKey);
|
|
51
|
+
const tokenAccount = await getAccount(this.connection, tokenAccountAddress);
|
|
52
|
+
const balance = new BigNumber(tokenAccount.amount.toString()).dividedBy(10 ** 6); // USDC has 6 decimals
|
|
53
|
+
if (balance.lt(amount)) {
|
|
54
|
+
this.logger.warn(`Insufficient ${currency} balance for payment. Required: ${amount}, Available: ${balance}`);
|
|
55
|
+
throw new InsufficientFundsError(currency, amount, balance, 'solana');
|
|
56
|
+
}
|
|
57
|
+
// Get the destination token account address (this will be the transactionId)
|
|
58
|
+
const destinationTokenAccount = await getAssociatedTokenAddress(USDC_MINT, receiverKey);
|
|
59
|
+
// Increase compute units to handle both memo and token transfer
|
|
60
|
+
// Memo uses ~6000 CUs, token transfer needs ~6500 CUs
|
|
61
|
+
const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
|
|
62
|
+
units: 50000,
|
|
63
|
+
});
|
|
64
|
+
const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({
|
|
65
|
+
microLamports: 20000,
|
|
66
|
+
});
|
|
67
|
+
const transaction = await createTransfer(this.connection, this.source.publicKey, {
|
|
68
|
+
amount: amount,
|
|
69
|
+
recipient: receiverKey,
|
|
70
|
+
splToken: USDC_MINT,
|
|
71
|
+
memo,
|
|
72
|
+
});
|
|
73
|
+
transaction.add(modifyComputeUnits);
|
|
74
|
+
transaction.add(addPriorityFee);
|
|
75
|
+
const transactionSignature = await sendAndConfirmTransaction(this.connection, transaction, [this.source]);
|
|
76
|
+
// Return transaction signature as transactionId and token account address as transactionSubId
|
|
77
|
+
return {
|
|
78
|
+
transactionId: transactionSignature,
|
|
79
|
+
transactionSubId: destinationTokenAccount.toBase58(),
|
|
80
|
+
chain: 'solana',
|
|
81
|
+
currency: 'USDC'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error instanceof InsufficientFundsError || error instanceof PaymentNetworkError) {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
// Wrap other errors in PaymentNetworkError
|
|
89
|
+
throw new PaymentNetworkError(`Payment failed on Solana network: ${error.message}`, error);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
if (!solanaEndpoint) {
|
|
93
|
+
throw new Error('Solana endpoint is required');
|
|
94
|
+
}
|
|
95
|
+
if (!sourceSecretKey) {
|
|
96
|
+
throw new Error('Source secret key is required');
|
|
97
|
+
}
|
|
98
|
+
this.connection = new Connection(solanaEndpoint, { commitment: 'confirmed' });
|
|
99
|
+
this.source = Keypair.fromSecretKey(bs58.decode(sourceSecretKey));
|
|
100
|
+
this.logger = logger ?? new ConsoleLogger();
|
|
101
|
+
}
|
|
102
|
+
getSourceAddress(_params) {
|
|
103
|
+
return this.source.publicKey.toBase58();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
class SolanaAccount {
|
|
108
|
+
constructor(solanaEndpoint, sourceSecretKey) {
|
|
109
|
+
if (!solanaEndpoint) {
|
|
110
|
+
throw new Error('Solana endpoint is required');
|
|
111
|
+
}
|
|
112
|
+
if (!sourceSecretKey) {
|
|
113
|
+
throw new Error('Source secret key is required');
|
|
114
|
+
}
|
|
115
|
+
const source = Keypair.fromSecretKey(bs58.decode(sourceSecretKey));
|
|
116
|
+
this.sourcePublicKey = source.publicKey.toBase58();
|
|
117
|
+
// Format accountId as network:address
|
|
118
|
+
this.accountId = `solana:${this.sourcePublicKey}`;
|
|
119
|
+
this.paymentMakers = [
|
|
120
|
+
new SolanaPaymentMaker(solanaEndpoint, sourceSecretKey)
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get sources for this account
|
|
125
|
+
*/
|
|
126
|
+
async getSources() {
|
|
127
|
+
return [{
|
|
128
|
+
address: this.sourcePublicKey,
|
|
129
|
+
chain: 'solana',
|
|
130
|
+
walletType: 'eoa'
|
|
131
|
+
}];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { SolanaAccount, SolanaPaymentMaker, ValidateTransferError };
|
|
136
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/solanaPaymentMaker.ts","../src/solanaAccount.ts"],"sourcesContent":[null,null],"names":["_ValidateTransferError"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Account, PaymentMaker } from '@atxp/client';
|
|
2
|
+
import type { AccountId, Source } from '@atxp/common';
|
|
3
|
+
export declare class SolanaAccount implements Account {
|
|
4
|
+
accountId: AccountId;
|
|
5
|
+
paymentMakers: PaymentMaker[];
|
|
6
|
+
private sourcePublicKey;
|
|
7
|
+
constructor(solanaEndpoint: string, sourceSecretKey: string);
|
|
8
|
+
/**
|
|
9
|
+
* Get sources for this account
|
|
10
|
+
*/
|
|
11
|
+
getSources(): Promise<Source[]>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=solanaAccount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solanaAccount.d.ts","sourceRoot":"","sources":["../src/solanaAccount.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAKtD,qBAAa,aAAc,YAAW,OAAO;IAC3C,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,OAAO,CAAC,eAAe,CAAS;gBAEpB,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM;IAiB3D;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAOtC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SolanaPaymentMaker } from './solanaPaymentMaker.js';
|
|
2
|
+
import { Keypair } from '@solana/web3.js';
|
|
3
|
+
import bs58 from 'bs58';
|
|
4
|
+
|
|
5
|
+
class SolanaAccount {
|
|
6
|
+
constructor(solanaEndpoint, sourceSecretKey) {
|
|
7
|
+
if (!solanaEndpoint) {
|
|
8
|
+
throw new Error('Solana endpoint is required');
|
|
9
|
+
}
|
|
10
|
+
if (!sourceSecretKey) {
|
|
11
|
+
throw new Error('Source secret key is required');
|
|
12
|
+
}
|
|
13
|
+
const source = Keypair.fromSecretKey(bs58.decode(sourceSecretKey));
|
|
14
|
+
this.sourcePublicKey = source.publicKey.toBase58();
|
|
15
|
+
// Format accountId as network:address
|
|
16
|
+
this.accountId = `solana:${this.sourcePublicKey}`;
|
|
17
|
+
this.paymentMakers = [
|
|
18
|
+
new SolanaPaymentMaker(solanaEndpoint, sourceSecretKey)
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get sources for this account
|
|
23
|
+
*/
|
|
24
|
+
async getSources() {
|
|
25
|
+
return [{
|
|
26
|
+
address: this.sourcePublicKey,
|
|
27
|
+
chain: 'solana',
|
|
28
|
+
walletType: 'eoa'
|
|
29
|
+
}];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { SolanaAccount };
|
|
34
|
+
//# sourceMappingURL=solanaAccount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solanaAccount.js","sources":["../src/solanaAccount.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;MAMa,aAAa,CAAA;IAKxB,WAAA,CAAY,cAAsB,EAAE,eAAuB,EAAA;QACzD,IAAI,CAAC,cAAc,EAAE;AACnB,YAAA,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC;QAChD;QACA,IAAI,CAAC,eAAe,EAAE;AACpB,YAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;QAClD;AACA,QAAA,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAClE,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE;;QAGlD,IAAI,CAAC,SAAS,GAAG,CAAA,OAAA,EAAU,IAAI,CAAC,eAAe,EAAe;QAC9D,IAAI,CAAC,aAAa,GAAG;AACnB,YAAA,IAAI,kBAAkB,CAAC,cAAc,EAAE,eAAe;SACvD;IACH;AAEA;;AAEG;AACH,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC;gBACN,OAAO,EAAE,IAAI,CAAC,eAAe;AAC7B,gBAAA,KAAK,EAAE,QAAQ;AACf,gBAAA,UAAU,EAAE;AACb,aAAA,CAAC;IACJ;AACD;;;;"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PaymentMaker } from '@atxp/client';
|
|
2
|
+
import { ValidateTransferError as _ValidateTransferError } from "@solana/pay";
|
|
3
|
+
import BigNumber from "bignumber.js";
|
|
4
|
+
import { Currency, AccountId, PaymentIdentifier, Destination } from '@atxp/common';
|
|
5
|
+
import { Logger } from '@atxp/common';
|
|
6
|
+
export declare const ValidateTransferError: typeof _ValidateTransferError;
|
|
7
|
+
export declare class SolanaPaymentMaker implements PaymentMaker {
|
|
8
|
+
private connection;
|
|
9
|
+
private source;
|
|
10
|
+
private logger;
|
|
11
|
+
constructor(solanaEndpoint: string, sourceSecretKey: string, logger?: Logger);
|
|
12
|
+
getSourceAddress(_params: {
|
|
13
|
+
amount: BigNumber;
|
|
14
|
+
currency: Currency;
|
|
15
|
+
receiver: string;
|
|
16
|
+
memo: string;
|
|
17
|
+
}): string;
|
|
18
|
+
generateJWT: ({ paymentRequestId, codeChallenge, accountId }: {
|
|
19
|
+
paymentRequestId: string;
|
|
20
|
+
codeChallenge: string;
|
|
21
|
+
accountId?: AccountId | null;
|
|
22
|
+
}) => Promise<string>;
|
|
23
|
+
makePayment: (destinations: Destination[], memo: string, _paymentRequestId?: string) => Promise<PaymentIdentifier | null>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=solanaPaymentMaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solanaPaymentMaker.d.ts","sourceRoot":"","sources":["../src/solanaPaymentMaker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAkB,qBAAqB,IAAI,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAG9F,OAAO,SAAS,MAAM,cAAc,CAAC;AACrC,OAAO,EAAe,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhG,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAMtC,eAAO,MAAM,qBAAqB,+BAAyB,CAAC;AAE5D,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAY5E,gBAAgB,CAAC,OAAO,EAAE;QAAC,MAAM,EAAE,SAAS,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAI1G,WAAW,GAAS,gDAA8C;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;KAAC,KAAG,OAAO,CAAC,MAAM,CAAC,CAelK;IAED,WAAW,GAAU,cAAc,WAAW,EAAE,EAAE,MAAM,MAAM,EAAE,oBAAoB,MAAM,KAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAyF7H;CACF"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { PaymentNetworkError, InsufficientFundsError } from '@atxp/client';
|
|
2
|
+
import { PublicKey, ComputeBudgetProgram, sendAndConfirmTransaction, Connection, Keypair } from '@solana/web3.js';
|
|
3
|
+
import { ValidateTransferError as ValidateTransferError$1, createTransfer } from '@solana/pay';
|
|
4
|
+
import { getAssociatedTokenAddress, getAccount } from '@solana/spl-token';
|
|
5
|
+
import bs58 from 'bs58';
|
|
6
|
+
import BigNumber from 'bignumber.js';
|
|
7
|
+
import { generateJWT, ConsoleLogger } from '@atxp/common';
|
|
8
|
+
import { importJWK } from 'jose';
|
|
9
|
+
|
|
10
|
+
// this is a global public key for USDC on the solana mainnet
|
|
11
|
+
const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
|
12
|
+
const ValidateTransferError = ValidateTransferError$1;
|
|
13
|
+
class SolanaPaymentMaker {
|
|
14
|
+
constructor(solanaEndpoint, sourceSecretKey, logger) {
|
|
15
|
+
this.generateJWT = async ({ paymentRequestId, codeChallenge, accountId }) => {
|
|
16
|
+
// Solana/Web3.js secretKey is 64 bytes:
|
|
17
|
+
// first 32 bytes are the private scalar, last 32 are the public key.
|
|
18
|
+
// JWK expects only the 32-byte private scalar for 'd'
|
|
19
|
+
const jwk = {
|
|
20
|
+
kty: 'OKP',
|
|
21
|
+
crv: 'Ed25519',
|
|
22
|
+
d: Buffer.from(this.source.secretKey.slice(0, 32)).toString('base64url'),
|
|
23
|
+
x: Buffer.from(this.source.publicKey.toBytes()).toString('base64url'),
|
|
24
|
+
};
|
|
25
|
+
const privateKey = await importJWK(jwk, 'EdDSA');
|
|
26
|
+
if (!(privateKey instanceof CryptoKey)) {
|
|
27
|
+
throw new Error('Expected CryptoKey from importJWK');
|
|
28
|
+
}
|
|
29
|
+
return generateJWT(this.source.publicKey.toBase58(), privateKey, paymentRequestId || '', codeChallenge || '', accountId);
|
|
30
|
+
};
|
|
31
|
+
this.makePayment = async (destinations, memo, _paymentRequestId) => {
|
|
32
|
+
// Filter to solana chain destinations
|
|
33
|
+
const solanaDestinations = destinations.filter(d => d.chain === 'solana');
|
|
34
|
+
if (solanaDestinations.length === 0) {
|
|
35
|
+
this.logger.debug('SolanaPaymentMaker: No solana destinations found, cannot handle payment');
|
|
36
|
+
return null; // Cannot handle these destinations
|
|
37
|
+
}
|
|
38
|
+
// Pick first solana destination
|
|
39
|
+
const dest = solanaDestinations[0];
|
|
40
|
+
const amount = dest.amount;
|
|
41
|
+
const currency = dest.currency;
|
|
42
|
+
const receiver = dest.address;
|
|
43
|
+
if (currency.toUpperCase() !== 'USDC') {
|
|
44
|
+
throw new PaymentNetworkError('Only USDC currency is supported; received ' + currency);
|
|
45
|
+
}
|
|
46
|
+
const receiverKey = new PublicKey(receiver);
|
|
47
|
+
this.logger.info(`Making payment of ${amount} ${currency} to ${receiver} on Solana from ${this.source.publicKey.toBase58()}`);
|
|
48
|
+
try {
|
|
49
|
+
// Check balance before attempting payment
|
|
50
|
+
const tokenAccountAddress = await getAssociatedTokenAddress(USDC_MINT, this.source.publicKey);
|
|
51
|
+
const tokenAccount = await getAccount(this.connection, tokenAccountAddress);
|
|
52
|
+
const balance = new BigNumber(tokenAccount.amount.toString()).dividedBy(10 ** 6); // USDC has 6 decimals
|
|
53
|
+
if (balance.lt(amount)) {
|
|
54
|
+
this.logger.warn(`Insufficient ${currency} balance for payment. Required: ${amount}, Available: ${balance}`);
|
|
55
|
+
throw new InsufficientFundsError(currency, amount, balance, 'solana');
|
|
56
|
+
}
|
|
57
|
+
// Get the destination token account address (this will be the transactionId)
|
|
58
|
+
const destinationTokenAccount = await getAssociatedTokenAddress(USDC_MINT, receiverKey);
|
|
59
|
+
// Increase compute units to handle both memo and token transfer
|
|
60
|
+
// Memo uses ~6000 CUs, token transfer needs ~6500 CUs
|
|
61
|
+
const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
|
|
62
|
+
units: 50000,
|
|
63
|
+
});
|
|
64
|
+
const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({
|
|
65
|
+
microLamports: 20000,
|
|
66
|
+
});
|
|
67
|
+
const transaction = await createTransfer(this.connection, this.source.publicKey, {
|
|
68
|
+
amount: amount,
|
|
69
|
+
recipient: receiverKey,
|
|
70
|
+
splToken: USDC_MINT,
|
|
71
|
+
memo,
|
|
72
|
+
});
|
|
73
|
+
transaction.add(modifyComputeUnits);
|
|
74
|
+
transaction.add(addPriorityFee);
|
|
75
|
+
const transactionSignature = await sendAndConfirmTransaction(this.connection, transaction, [this.source]);
|
|
76
|
+
// Return transaction signature as transactionId and token account address as transactionSubId
|
|
77
|
+
return {
|
|
78
|
+
transactionId: transactionSignature,
|
|
79
|
+
transactionSubId: destinationTokenAccount.toBase58(),
|
|
80
|
+
chain: 'solana',
|
|
81
|
+
currency: 'USDC'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error instanceof InsufficientFundsError || error instanceof PaymentNetworkError) {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
// Wrap other errors in PaymentNetworkError
|
|
89
|
+
throw new PaymentNetworkError(`Payment failed on Solana network: ${error.message}`, error);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
if (!solanaEndpoint) {
|
|
93
|
+
throw new Error('Solana endpoint is required');
|
|
94
|
+
}
|
|
95
|
+
if (!sourceSecretKey) {
|
|
96
|
+
throw new Error('Source secret key is required');
|
|
97
|
+
}
|
|
98
|
+
this.connection = new Connection(solanaEndpoint, { commitment: 'confirmed' });
|
|
99
|
+
this.source = Keypair.fromSecretKey(bs58.decode(sourceSecretKey));
|
|
100
|
+
this.logger = logger ?? new ConsoleLogger();
|
|
101
|
+
}
|
|
102
|
+
getSourceAddress(_params) {
|
|
103
|
+
return this.source.publicKey.toBase58();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { SolanaPaymentMaker, ValidateTransferError };
|
|
108
|
+
//# sourceMappingURL=solanaPaymentMaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solanaPaymentMaker.js","sources":["../src/solanaPaymentMaker.ts"],"sourcesContent":[null],"names":["_ValidateTransferError"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atxp/solana",
|
|
3
|
+
"version": "0.8.3",
|
|
4
|
+
"description": "ATXP Solana - Solana blockchain support for ATXP",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/atxp-dev/sdk.git",
|
|
9
|
+
"directory": "packages/atxp-solana"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"require": "./dist/index.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "rollup -c",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"lint": "eslint . --ext .ts",
|
|
30
|
+
"lint:fix": "eslint . --ext .ts --fix",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"prepack": "npm run build && npm run typecheck",
|
|
33
|
+
"pack:dry": "npm pack --dry-run"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@atxp/client": "0.8.3",
|
|
37
|
+
"@atxp/common": "0.8.3",
|
|
38
|
+
"@solana/pay": "^0.2.5",
|
|
39
|
+
"@solana/web3.js": "^1.98.1",
|
|
40
|
+
"bignumber.js": "^9.3.0",
|
|
41
|
+
"bs58": "^6.0.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.13.0",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
46
|
+
"@typescript-eslint/parser": "^8.38.0",
|
|
47
|
+
"eslint": "^9.32.0",
|
|
48
|
+
"typescript": "^5.7.3",
|
|
49
|
+
"vitest": "^3.0.9"
|
|
50
|
+
}
|
|
51
|
+
}
|