forked from Nova-reward/Nova-Rewards
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsendRewards.js
More file actions
98 lines (88 loc) · 2.89 KB
/
Copy pathsendRewards.js
File metadata and controls
98 lines (88 loc) · 2.89 KB
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
require('dotenv').config();
const {
Keypair,
TransactionBuilder,
Operation,
Memo,
Networks,
BASE_FEE,
StrKey,
} = require('stellar-sdk');
const { server, NOVA } = require('./stellarService');
const { verifyTrustline } = require('./trustline');
const NETWORK_PASSPHRASE =
process.env.STELLAR_NETWORK === 'mainnet'
? Networks.PUBLIC
: Networks.TESTNET;
/**
* Distributes NOVA tokens from the Distribution Account to a customer wallet.
* Signs the transaction server-side using DISTRIBUTION_SECRET.
* Requirements: 3.2, 3.3, 3.6
*
* @param {object} params
* @param {string} params.toWallet - Recipient's Stellar public key
* @param {string} params.amount - Amount of NOVA to send (e.g. "10.0000000")
* @returns {Promise<{ success: boolean, txHash: string }>}
* @throws {Error} with error.code set to 'no_trustline' or 'insufficient_balance'
*/
async function distributeRewards({ toWallet, amount }) {
// 0. Validate recipient address before any network calls
if (!toWallet || !StrKey.isValidEd25519PublicKey(toWallet)) {
const err = new Error(
`Invalid Stellar address: "${toWallet}". Must be a valid Ed25519 public key.`
);
err.code = 'invalid_address';
throw err;
}
// 1. Verify recipient has a NOVA trustline before attempting payment
const { exists } = await verifyTrustline(toWallet);
if (!exists) {
const err = new Error(
'Recipient does not have a NOVA trustline. They must create one before receiving rewards.'
);
err.code = 'no_trustline';
throw err;
}
// 2. Load the Distribution Account
const distributionKeypair = Keypair.fromSecret(process.env.DISTRIBUTION_SECRET);
const distributionAccount = await server.loadAccount(
distributionKeypair.publicKey()
);
// 3. Check Distribution Account has sufficient NOVA balance
const novaBalance = distributionAccount.balances.find(
(b) =>
b.asset_type !== 'native' &&
b.asset_code === NOVA.code &&
b.asset_issuer === NOVA.issuer
);
const available = novaBalance ? parseFloat(novaBalance.balance) : 0;
if (available < parseFloat(amount)) {
const err = new Error(
`Distribution Account has insufficient NOVA balance. Available: ${available}, Requested: ${amount}`
);
err.code = 'insufficient_balance';
throw err;
}
// 4. Build, sign, and submit the payment transaction
const transaction = new TransactionBuilder(distributionAccount, {
fee: BASE_FEE,
networkPassphrase: NETWORK_PASSPHRASE,
})
.addOperation(
Operation.payment({
destination: toWallet,
asset: NOVA,
amount: String(amount),
})
)
.addMemo(Memo.text('NovaRewards distribution'))
.setTimeout(180)
.build();
transaction.sign(distributionKeypair);
const result = await server.submitTransaction(transaction);
return {
success: true,
txHash: result.hash,
};
}
module.exports = { distributeRewards };