The Qtum Sparknet Faucet

I've made a smart contract for the Qtum Sparknet testnet. It functions as a basic faucet. It doesn't help if you don't already have some coins because gas is required to use it. However, if you need more coins you can use this faucet to retrieve 100 coins at a time. You can also use it to send coins to other addresses not owned by you.

Here is the contract code, it's very simple:

pragma solidity ^0.4.11;

contract QtumFaucet {
    uint constant COIN = 100000000;
    function deposit() public payable{
    }
    function withdraw() public{
        uint amount = 100 * COIN;
        if(this.balance < 100 * COIN){
            amount = this.balance;
        }
        if(!msg.sender.send(amount)){
            throw;
        }
    }
    function send(address a) public{
        uint amount = 100 * COIN;
        if(this.balance < 100 * COIN){
            amount = this.balance;
        }
        if(!a.send(amount)){
            throw;
        }
   }

   function() payable{}
}

This contract generates this ABI JSON file:

[{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"a","type":"address"}],"name":"send","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"type":"function"},{"payable":true,"type":"fallback"}]

This contract is deployed to the sparknet at address f28aa77dd07ee8a1288ab6f41b23ebf6d605dc3e.

To initially fill this contract I will use "ethabi" like so:

ethabi encode function ~/faucet.json deposit
d0e30db0

I deposit 1000 tokens to the faucet now using sendtocontract:

./qtum-cli sendtocontract f28aa77dd07ee8a1288ab6f41b23ebf6d605dc3e d0e30db0 1000

After this transaction has confirmed we can actually withdraw some funds from the faucet contract. So, lets get an address:

./qtum-cli getaccountaddress x
QUvMQdxMxUuCQ7zLHvAcfmhFWyP9kkjr8C

So, we now use that to construct our ABI data using ethabi again:

ethabi encode function ~/faucet.json send -p QUvMQdxMxUuCQ7zLHvAcfmhFWyP9kkjr8C
error: Tokenizer(FromHex(Invalid character 'Q' at position 0))

Now we face a problem. Solidity doesn't actually use base58 addresses, it uses hex addresses like in Ethereum. This includes the ABI data as well. We must first convert our base58 address QUvMQdxMxUuCQ7zLHvAcfmhFWyP9kkjr8C to a hex address. A recent update to Qtum has added two RPC calls for this purpose: gethexaddress and fromhexaddress.

./qtum-cli gethexaddress QUvMQdxMxUuCQ7zLHvAcfmhFWyP9kkjr8C
5b3a45e69dbbd7b3a9db31a8c855040f35793929

What this does is actually takes the data encoded in the base58 address, validates that it is not corrupted and is the right size, and then will return that data as a hex string. This hex string is the address format that Solidity and thus the ABI uses. So, now we fix our mistake:

ethabi encode function ~/faucet.json send -p 5b3a45e69dbbd7b3a9db31a8c855040f35793929
3e58c58c0000000000000000000000005b3a45e69dbbd7b3a9db31a8c855040f35793929

Now we can use callcontract so that we know how much gas we need to send (or you can skip this if you're confident the default is enough)

./qtum-cli callcontract $FAUCET 3e58c58c0000000000000000000000005b3a45e69dbbd7b3a9db31a8c855040f35793929 
{
  "address": "f28aa77dd07ee8a1288ab6f41b23ebf6d605dc3e",
  "executionResult": {
    "gasUsed": 55978,
    "excepted": "None",
    "newAddress": "f28aa77dd07ee8a1288ab6f41b23ebf6d605dc3e",
    "output": "",
    "codeDeposit": 0,
    "gasRefunded": 0,
    "depositSize": 0,
    "gasForDeposit": 0
  },
  "transactionReceipt": {
    "stateRoot": "4118b6d0685de70ef82c7905e7ab2d691470285b7c56506ffca9b1db21bcb278",
    "gasUsed": 55978,
    "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "log": [
    ]
  }
}

Under execution result, the gasUsed field is what we are interested in. It's always safer to send a little more gas than is needed to avoid out of gas exceptions. So, we will use 60,000 for the gas limit.

./qtum-cli sendtocontract $FAUCET 3e58c58c0000000000000000000000005b3a45e69dbbd7b3a9db31a8c855040f35793929 0 60000
{
  "txid": "cb7e8ef370a05665d5dd43d1134b8d0833d1c746d2d618162727c54e0f5a6ef5",
  "sender": "QWqFJB4EUhbBJpGnnnjaeR1mdUJdr6fWkV",
  "hash160": "703357de0cad939a528035cd319f849067fce2c7"
}

You can look at the results on the block explorer. Here is the contract execution. If we look at the block this transaction was included in, we see immediately after the execution transaction we have the Account Abstraction Layer generated transaction which actually sends 100 Qtum to our intended address, QUvMQdxMxUuCQ7zLHvAcfmhFWyP9kkjr8C. Further more, if we look at the coinstake transaction we can see our gas refund as the last output, an output of 0.0004022 Qtum sent to address QWqFJB4EUhbBJpGnnnjaeR1mdUJdr6fWkV.

And finally, in my wallet I also see the 100 tokens that were sent.

This contract is still alive and I'll monitor it and put more coins into it. So join in on the fun and deposit some coins and withdraw them. It's a pretty cool little contract that I made in about 10 minutes.

Posted: 6/30/2017 9:44:54 PM