-
Notifications
You must be signed in to change notification settings - Fork 2
/
ilp-plugin-xrp-payment.js
103 lines (91 loc) · 3.43 KB
/
ilp-plugin-xrp-payment.js
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
99
100
101
102
103
const { RippleAPI } = require('ripple-lib')
const { deriveAddress, deriveKeypair } = require('ripple-keypairs')
const { createSubmitter } = require('ilp-plugin-xrp-paychan-shared')
const BigNumber = require('bignumber.js')
const PluginPayment = require('..') // require('ilp-plugin-payment')
class PluginXrpPayment extends PluginPayment {
constructor (opts) {
super(opts)
if (!opts.secret) {
throw new Error('opts.secret must be defined')
}
// Parameters to connect to the network.
this._secret = opts.secret
this._address = opts.address || deriveAddress(deriveKeypair(opts.secret).publicKey)
this._xrpServer = opts.xrpServer || 'wss://s1.ripple.com'
this._api = new RippleAPI({ server: this._xrpServer })
this._txSubmitter = createSubmitter(this._api, this._address, this._secret)
// This destination tag allows us to determine which payments are for us.
// If we didn't have it, then a peer could send a payment to our address
// and multiple plugins might register the incoming money. If you don't
// have a mechanism to do this, then be very careful that multiple plugins
// don't run on the same account
this._destinationTagMap = new Map()
this._userIdMap = new Map()
}
async _userIdToDestinationTag (userId) {
if (!this._destinationTagMap.get(userId)) {
const tag = crypto.randomBytes(4).readUInt32BE(0)
this._destinationTagMap.set(userId, tag)
this._userIdMap.set(tag, userId)
}
return this._destinationTagMap.get(userId)
}
async _destinationTagToUserId (tag) {
if (!this._userIdMap.get(tag)) {
throw new Error('no user id found for tag. tag=' + tag)
}
return this._userIdMap.get(tag)
}
async connectPayment () {
await this._api.connect()
await this._api.connection.request({
command: 'subscribe',
accounts: [ this._address ]
})
// This is how we detect an incoming transaction. You'll need some equivalent of this
// that calls this._handleMoney whenever a payment destined for this plugin comes in.
this._api.connection.on('transaction', ev => {
if (ev.validated && ev.transaction &&
ev.transaction.TransactionType === 'Payment' &&
ev.transaction.Destination === this._address &&
ev.transaction.Amount.currency === 'XRP') {
const userId = this._destinationTagToUserId(ev.transaction.DestinationTag)
const value = new BigNumber(ev.transaction.Amount.value).times(1e6).toString()
this.emitAsync('money', userId, value)
}
})
}
// Return whatever details are needed in order to pay to this plugin's
// account. They'll be returned when the other side calls
// _getPaymentDetails()
async getPaymentDetails (userId) {
return {
address: this._address,
destinationTag: this._userIdToDestinationTag(userId)
}
}
// Sends a payment. Details is the return value from getPaymentDetails for
// the other side.
async sendPayment (details, amount) {
const xrpAmount = new BigNumber(amount).div(1e6).toString()
await this._txSubmitter('preparePayment', {
source: {
address: this._address,
maxAmount: {
value: xrpAmount,
currency: 'XRP'
}
},
destination: {
address: details.address,
tag: details.destinationTag,
amount: {
value: xrpAmount,
currency: 'XRP'
}
}
})
}
}
module.exports = PluginXrpPayment