First demo of Mainnet Bitcoin Cash library

10 438
Avatar for mainnet
4 years ago (Last updated: 3 years ago)

So, we finally have a first demo of Mainnet Bitcoin Cash library.

It has been 2 months since the original FlipStarter has been funded. It took so long, because we have hit so many dead-ends while developing it (Kudos to 2qx for so much work done!) and had to change the interfaces too many times, because something was inconsistent.

Note that this is an early prototype, so things will be changing under you if you try to use it now.

Here be dragons!

Seriously, we don't recommend that you use it right now. It's unstable and some APIs will definitely change (as noted below). Use at your own risk.

Demo of JavaScript library

Finally! The demo is here:

https://jsfiddle.net/ghn19jmu/2/

It shows:

  • How to create a TestNet wallet

  • Wait for a transaction

  • Send a specific amount

  • Send the full amount

  • Get balances in BCH, satoshis and USD

  • Get transaction IDs for recent sends

Note: it donates any money left to Chris Troutner's Bitcoin Cash TestNet faucet (please don't drain it!).

You can use Chris' TestNet faucet with the demo (once per 24 hours), because it'll send all your TestNet satoshis back to the faucet.

Video of the demo

Or you can watch it as a video:

Sending is slower than usual, because of use of clusters, see below. You can adjust it to be fast, but less reliable.

These 1,273 BCH you see in the video are TestNet coins, they aren't worth anything. So, stop stalking me :)

A few highlights from the JavaScript API:

<script src="https://mainnet.cash/dist/mainnet-0.0.1-rc.js"></script>

If you want to yell at me for using <script src and its security, then you already know what to do - host the .js file yourself :)

In the meantime, the npm package is coming.

We use a lot of async functions, so wrap it in async function if you want to use it in plain browser:

async function run() {
  // your code goes here
}

run().catch(e => console.log(e));

Create a new wallet:

const wallet = await TestNetWallet.newRandom(); // new Testnet wallet
// ... or
const wallet = await Wallet.newRandom(); // production/mainnet wallet
const wallet = await RegTestWallet.newRandom(); // for local Bitcoin Cash node

Under the hood we use the awesome electrum cash library by Jonathan Silverblood, so by default you are protected by the cluster agreement available in the library.

This means that you are always connected to multiple redundant servers (Fulcrums!) at any time and they must agree on what's happening before you'll see any data. (Or you can change it and connect to a single instance only for high-speed) Kudos, Jonathan!

We also use Rosco Kalis' CashScript's Network Provider, so actually you could use electrum cash library, BitboxNetworkProvider, Chris Troutner's FullStackNetworkProvider or even write your own Custom NetworkProviders. (Yes, CashScript is coming to mainnet!) Kudos, Rosco!

Oh, yeah, and by default we connect to Fulcrums (by Calin Cullinau), which are these awesome high-performance servers, so even if you have tons of UTXOs, you'll get your response fast! Kudos, Calin!

We also use Jason Dreyzehner's libauth, which is awesome to build Bitcoin Cash transactions. Kudos, Jason!

Huge kudos to 2qx who managed to tie it all together. Kudos!

So, to re-iterate the goodies:

Feel the power yet?

How to use it

What's the address?

wallet.getDepositAddress()

What's the private key?

wallet.privateKeyWif

How much money do we have there?

await wallet.getBalance('bch') // in Bitcoin Cash
await wallet.getBalance('sat') // in satoshis
await wallet.getBalance('usd') // in USD (doesn't really make sense on TestNet)

Now, you can create a second wallet the same way and send some money to it:

const result = await wallet.send([ 
   [wallet2.getDepositAddress(), 500, 'satoshis'], 
]);

The change is automatically calculated and sent back to your wallet (fees are set at 1sat/b).

Yes, you can send to multiple addresses at once. The result object not only has the transaction ID, but also the new balances:

result.txId
result.balance.bch
result.balance.sat
result.balance.usd

Wait for $0.05 (better way coming soon):

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

while((await wallet.getBalance('usd')) < 0.05) { 
  await sleep(0.1); 
}  

...or you can simply hammer the servers :) Though, it's not nice.

while((await wallet.getBalance('usd') < 0.05) {}

Send the full amount (except the fee of about ~$0.0015):

await wallet.sendMax('bchtest:qzt6sz836wdwscld0pgq2prcpck2pssmwge9q87pe9');

How much can we send?

await wallet.getMaxAmountToSend()

Frankly, this is more than enough to build something like read.cash with in-browser wallets :)

Ok, let's move on to the REST server.

REST server

Here be more dragons!

The REST server is available at https://rest-unstable.mainnet.cash/

Did you notice the "unstable" part? Hope that tells you something :)

Note that by default, you are sending your private key to the server.
To use it securely, you need to be running your own server! (It's not that hard, see below)

The API pretty useful and self-documenting (ok, the send method docs are missing for now, sorry, we'll fix it, there's walletId and to, which is an array of objects that have cashaddr, amount and unit = sat, bch or usd), you can do everything you can do with the JavaScript library, but via REST:

  • Create a TestNet/Mainnet/Regtest wallet

  • Send a specific amount

  • Send the full amount

  • Get balances in BCH, satoshis and USD

  • Get transaction IDs for your sends

...also some other things like getting QR codes for addresses as images.

How to run your own server

docker run -d --env WORKERS=5 -p 127.0.0.1:3000:80 mainnet/mainnet-rest

or

git clone https://github.com/mainnet-cash/mainnet-js.git
cd mainnet-js
npm i
npm run api:build:server
npm run build
(cd generated/serve && npm i)
PORT=3000 WORKERS=5 npm run api:serve:cluster

Warning. Each worker takes about 70-100MB memory, which seems to be the norm for express.js servers :(

Oh and in case you are wondering, the better documentation and video tutorials are coming. Just a bit later.

Other languages

Did I mention dragons yet?

So, to generate bindings for the REST server, you need to generate them. Oh, you better believe the dragons are there.

Here's an example to generate PHP bindings:

npm run api:build:client php

Replace php above in two places with any language:

  • android, c

  • cpp-qt5-client, cpp-restsdk, cpp-tizen, cpp-ue4

  • csharp, csharp-netcore

  • dart

  • elixir

  • go

  • haskell-http-client

  • java

  • javascript

  • kotlin

  • objc

  • php

  • python

  • r

  • ruby

  • rust

  • typescript

  • typescript-node

  • Full list here

The bindings are a bit awkward, But they should work. More information will come soon.

Here's an example in PHP:

$walletId = 'wif:mainnet:2SamS....';

$walletApi = new WalletApi();
$balance = $walletApi->balance(['wallet_id' => $walletId]);
print($balance->usd);

This calls the /wallet/balance endpoint as described here.

$config = new Configuration();
//$config->setHost('https://rest-unstable.mainnet.cash/v1');
$config->setHost('http://localhost:3000/v1');
$client = new WalletApi(null, $config);

// new wallet
$wallet = $client->createWallet(['network' => 'testnet']);
$walletId = $wallet->getWalletId();

// deposit address
$client->depositAddress(['walletId' => $walletId]);

// balance
$balance = $client->balance(['walletId' => $walletId]);
print($balance->getUsd());

// send
$result = $client->send([
   'walletId' => $walletId, 
   'to' => [
     [
       'cashaddr' => 'bitcoincash:qp...',
       'value' => 100,
       'unit' => 'usd', 
       // this call might change to ['bitcoincash:qp...', '100', 'usd']
     ],
   ]
]);

(Code examples are for example only, I haven't tested them properly yet)

We hope that later people will write better wrappers in their languages, that will give people better use.

Money

Money spent from the original FlipStarter: ~15%

As I said, you can't hire the cheapest developers to do this stuff, and I underestimated badly how much time it will take. I really hope that we can get a lot of the original promise done, but I'm not as optimistic as I was when I started the FlipStarter, we're probably done with ~2% of the stuff, having spent about 15%. Not great. So much work ahead.

But frankly, I still see it as a great success. Even if it was just like this, it's VERY useful and can help a lot of people.

Next steps: polish the basics, fix minor bugs, stabilize it, write better docs... and hopefully then, next stop is WebHooks and escrow contracts (incl. CashScript).

As far as I have seen - this is the easiest way to interact with Bitcoin Cash blockchain. And probably the only one that is working with TestNet and RegTest (locally deployed Bitcoin Cash Node (yes, BCHN), so that you can run automated tests using all the same libraries, without worrying about getting TestNet coins or managing them).

27
$ 1016.57
$ 1000.00 from @RogerVer
$ 10.00 from @jtoomim
$ 2.00 from @iamnotaclown
+ 7
Avatar for mainnet
4 years ago (Last updated: 3 years ago)

Comments

Really appreciate the update and continued transparency. Only some flipstarter campaigns have followed up like this.

And this looks great!

$ 0.00
4 years ago

Thank you! :)

$ 0.00
4 years ago

Alright, we're going underway! A new way to work with Bitcoin Cash. Can we make smart contracts for SLP Tokens soon?

Also, can we have a way to essentially have a donation script, where you don't need to give a set of BCH? I mean, I can just make it that it's a loop until conditions were met so...

$ 0.00
4 years ago

I think I published the plan in the last article: https://sigma.rcimg.net/images/c/9/c/mainnet/e36fc888/10813991611fd9e967b8da81ae04ab2d.png

Combining SLP and CashScript should be possible, but it might take a few months, these things take time :(

Also, can we have a way to essentially have a donation script, where you don't need to give a set of BCH?

Do you mean like "wait for any transaction to come"? I don't quite understand.

$ 0.00
4 years ago

I meant that the BCH request doesn'y needs a specific amount, so you can like click a button, send BCH here, then like accept if valid amount

$ 0.00
4 years ago

Well, this is a bit above mainnet's abstraction level. mainnet is a low-level library that you use to build these things. It's entirely possible, we'll have some tutorials on how to do that, but it's not one line of code, of course, especially the user interface part (a button, a reaction to that).

$ 0.00
4 years ago

Seriously, we don't recommend that you use it right now. It's unstable and some APIs will definitely change (as noted below). Use at your own risk.

Any update sir?

$ 0.00
4 years ago

Thank you everyone who donated! @RogerVer, wow! Thanks for a very generous tip!

$ 0.00
4 years ago

Instead of:

while((await wallet.getBalance('usd')) < 0.05) { 
  await sleep(0.1); 
}

You should probably just bake that into the libary and let users:

await wallet.waitForBalance('usd', 0.05);
$ 0.00
4 years ago

Yes, you can note that there's a comment near that block:

// got to use this until we have a better implementation of await wallet.waitForTransaction();

waitForBalance is also a good idea! Thanks!

$ 0.00
4 years ago