-
Notifications
You must be signed in to change notification settings - Fork 94
Writing chatbots for Byteball
Chatbots communicate with users and offer various services. The services are usually connected with payments.
= Prerequisites
To run a chatbot, you need a headless node. Headless nodes are full nodes by default. A subset of the functionality might work in light nodes too, but keep in mind that it was designed for full nodes only.
Create a new node.js package for your bot. You will definitely need modules from byteballcore
(add it to your project's dependencies) and if you are going to send payments, you will also need headless-byteball
. Your package.json
should list these dependencies:
"dependencies": {
"headless-byteball": "git+https://github.com/byteball/headless-byteball.git",
"byteballcore": "^0.2.33",
.....
}
In your conf (conf.js or conf.json) specify your bot name and a pairing secret that will be part of your pairing code:
exports.deviceName = 'My test bot';
exports.permanent_paring_secret = '0000';
When you start your node, it will print its full pairing code:
====== my pairing code: A2WMb6JEIrMhxVk+I0gIIW1vmM3ToKoLkNF8TqUV5UvX@byteball.org/bb#0000
Publish this pairing code on your website as a link with byteball:
scheme, users will be able to open a chat with your bot by clicking your link (the link opens in their Byteball app and starts a chat):
<a href="byteball:A2WMb6JEIrMhxVk+I0gIIW1vmM3ToKoLkNF8TqUV5UvX@byteball.org/bb#0000">Chat with my test bot</a>
= Receiving chat messages
To receive chat messages, subscribe to 'text' events on event bus:
var eventBus = require('byteballcore/event_bus.js');
eventBus.on('text', function(from_address, text){
// your code here
});
from_address
is user's device address (not to be confused with payment addresses), text
is his message.
= Sending chat messages
var device = require('byteballcore/device.js');
device.sendMessageToDevice(user_device_address, 'text', 'Text message from bot to user');
= Receiving pairing notifications When a user pairs his device with your bot (e.g. by clicking the link to your bot), you receive a pairing notification and can welcome the user:
eventBus.on('paired', function(from_address){
var device = require('byteballcore/device.js');
device.sendMessageToDevice(from_address, 'text', getMyWelcomeText());
});
= Commands To give access to predefined commands, format your responses this way:
click this link: [Command name](command:command code)
The user will see the text in square brackets "Command name", it will be highlighted as a link, and when the user clicks it, his app will send command code
text to your bot.
= Requesting payments When you include a valid Byteball address anywhere in the text of your response to the user, the address will be automatically highlighted in the user's chat window, and after clicking it the user will be able to pay arbitrary amount of arbitrary asset to this address.
When you want to request a specific amount of a specific asset, format your payment request this way:
Any text before [payment description, will be ignored](byteball:YOURBYTEBALLADDRESS?amount=123000&asset=base) any text after
Amount is in the smallest units, such as bytes. If you omit &asset=...
part, base asset (bytes) is assumed. If you want to request payment in another asset, indicate its identifier such as oj8yEksX9Ubq7lLc+p6F2uyHUuynugeVq4+ikT67X6E=
for blackbytes (don't forget to url-encode it).
You will likely want to generate a unique payment address per user, per transaction. This code sample might help:
var walletDefinedByKeys = require('byteballcore/wallet_defined_by_keys.js');
walletDefinedByKeys.issueNextAddress(wallet, 0, function(objAddress){
var byteball_address = objAddress.address;
// work with this address, then send it over to the user
device.sendMessageToDevice(user_device_address, 'text', "Please pay to "+byteball_address);
});
= Waiting for payments If you include a headless wallet
var headlessWallet = require('headless-byteball');
you can get notified when any of your addresses receives a payment
eventBus.on('new_my_transactions', function(arrUnits){
// react to receipt of payment(s)
});
arrUnits
is an array of units (more accurately, unit hashes) that contained any transaction involving your addresses. The event new_my_transactions
is triggered for outgoing transaction too, you should check if the new transaction credits one of the addresses you are expecting payments to.
= Waiting for finality of payments
To get notified when any of your transactions become stable (confirmed), subscribe to my_transactions_became_stable
event:
eventBus.on('my_transactions_became_stable', function(arrUnits){
// react to payment(s) becoming stable
});
arrUnits
is again the array of units that just became stable and they contained at least one transaction involving your addresses.
Alternatively, you can subscribe to event mci_became_stable
which is emitted each time a new main chain index (MCI) becomes stable:
eventBus.on('mci_became_stable', function(mci){
// check if there are any units you are interested in that had this MCI and react to their becoming stable
});
= Sending payments
To send payments, you need to include a headless wallet
var headlessWallet = require('headless-byteball');
and use this function:
headlessWallet.issueChangeAddressAndSendPayment(asset, amount, user_byteball_address, user_device_address, function(err, unit){
if (err){
// something went wrong, maybe put this payment on a retry queue
return;
}
// handle successful payment
});
asset
is the asset you are paying in (null
for bytes), amount
is payment amount in the smallest units. If the payment was successful, you get its unit
in the callback and can save it or watch further events on this unit.