ZR::BitcoinAddress ZrSatoshiBitcoin::mkOrderAddress( const ZR::ZR_Number & amount )
{
    std::string addr = newAddress();
    if( addr.empty() )
        return addr;

    try{
        JsonRpc rpc( m_settings );
        JsonRpc::JsonData res = rpc.executeRpc ( "sendtoaddress", addr, JsonRpc::JsonData( amount.toDouble() ) );
        // TODO: Error handling
        std::string id = res.asString();

        // make sure the Satoshi client does not touch "id"
        // this will go away if the Satoshi client is restarted
        // may be unnecessary for other implementations of this class, e.g. libbitcoin
        JsonRpc::JsonData addrArray( Json::arrayValue );
        addrArray.append( addr );
        JsonRpc::JsonData res2 = rpc.executeRpc ( "listunspent", 0, 999999, addrArray );
        unsigned int vout = res2[0u][ "vout" ].asUInt();
        JsonRpc::JsonData lockObjArray( Json::arrayValue );
        JsonRpc::JsonData lockObj;
        lockObj[ "txid" ] = id;
        lockObj[ "vout" ] = vout;
        lockObjArray.append( lockObj );
        JsonRpc::JsonData res1 = rpc.executeRpc ( "lockunspent", true, lockObjArray );
    }
    catch( std::runtime_error e ){
        g_ZeroReservePlugin->placeMsg( std::string( "Exception caught at " ) + __func__ + ": " + e.what() + " Cannot make an order address. Insufficient funds? If you have enough, try restarting the Satoshi Client." );
        std::cerr << "Zero Reserve: " << __func__ << ": Exception caught: " << e.what() << std::endl;
        print_stacktrace();
        return std::string();
    }
    return addr;
}
/**
 * Sign a message with this address.  This may throw if the address
 * is invalid, the wallet locked or the private key is not owned.
 * @param msg The message that should be signed.
 * @return The message's signature.
 * @throws NoPrivateKey if this address is not owned.
 * @throws std::runtime_error if the address is invalid or the wallet locked.
 */
std::string
CoinInterface::Address::signMessage (const std::string& msg) const
{
  if (!valid)
    throw std::runtime_error ("Can't sign with invalid address.");

  try
    {
      const JsonRpc::JsonData res = rpc->executeRpc ("signmessage", addr, msg);
      return res.asString ();
    }
  catch (const JsonRpc::RpcError& exc)
    {
      switch (exc.getErrorCode ())
        {
        case -13:
          throw std::runtime_error ("Need to unlock the wallet first.");

        case -3:
          {
            std::ostringstream msg;
            msg << "You don't have the private key of " << addr << " in order"
                << " to sign messages with that address.";
            throw NoPrivateKey (msg.str ());
          }

        default:
          throw exc;
        }
    }
}
void ZrSatoshiBitcoin::loadWallets( std::vector< ZR::MyWallet *> & wallets )
{
    JsonRpc rpc( m_settings );
    try{
        JsonRpc::JsonData res = rpc.executeRpc ("listaddressgroupings");
        for( nmcrpc::JsonRpc::JsonData::iterator it1 = res.begin(); it1 != res.end(); it1++ ){
            JsonRpc::JsonData res0 = *it1;
            assert (res0.isArray());
            for( nmcrpc::JsonRpc::JsonData::iterator it2 = res0.begin(); it2 != res0.end(); it2++ ){
                JsonRpc::JsonData res1 = *it2;
                JsonRpc::JsonData res2 = res1[ 0u ];
                ZR::BitcoinAddress address = res2.asString();

                JsonRpc::JsonData res21 = res1[ 1u ];
                ZR::ZR_Number balance = res21.asDouble();
                ZR::MyWallet * wallet = new SatoshiWallet( address, balance );
                wallets.push_back( wallet );
            }
        }
    }
    catch( std::runtime_error e ){
        std::cerr << "Zero Reserve: " << __func__ << ": Exception caught: " << e.what() << std::endl;
        print_stacktrace();
    }
}
/**
 * Query for the number of confirmations a transaction has.
 * @param txid The transaction id to check for.
 * @return Number of confirmations the transaction has.
 * @throws JsonRpc::RpcError if the tx is not found.
 */
unsigned
CoinInterface::getNumberOfConfirmations (const std::string& txid)
{
  const JsonRpc::JsonData res = rpc.executeRpc ("gettransaction", txid);
  assert (res.isObject ());

  return res["confirmations"].asInt ();
}
const ZR::BitcoinAddress ZrSatoshiBitcoin::newAddress() const
{
    std::string addr;
    try{
        JsonRpc rpc( m_settings );
        JsonRpc::JsonData resAddr = rpc.executeRpc ( "getnewaddress" );
        addr = resAddr.asString();
    }
    catch( std::runtime_error e ){
        std::cerr << "Zero Reserve: " << __func__ << ": Exception caught: " << e.what() << std::endl;
        g_ZeroReservePlugin->placeMsg( std::string( "Exception caught at " ) + __func__ + ": " + e.what() + " Cannot create new Bitcoin address." );
        print_stacktrace();
    }
    return addr;
}
ZR::MyWallet * ZrSatoshiBitcoin::mkWallet( ZR::MyWallet::WalletType wType )
{
    JsonRpc rpc( m_settings );
    try{
        if( wType == ZR::MyWallet::WIFIMPORT ){
            JsonRpc::JsonData res = rpc.executeRpc ( "getnewaddress" );
            ZR::BitcoinAddress address = res.asString();
            return new SatoshiWallet( address, 0 );
        }
    }
    catch( std::runtime_error e ){
        std::cerr << "Zero Reserve: " << __func__ << ": Exception caught: " << e.what() << std::endl;
        print_stacktrace();
    }
    return NULL;
}
/**
 * Check a message signature against this address.  If this address
 * is invalid, false is returned.
 * @param msg The message that should be signed.
 * @param sig The message's signature.
 * @return True iff the signature matches the message.
 */
bool
CoinInterface::Address::verifySignature (const std::string& msg,
                                         const std::string& sig) const
{
  if (!valid)
    return false;

  try
    {
      JsonRpc::JsonData res = rpc->executeRpc ("verifymessage", addr, sig, msg);
      return (res.isBool () && res.asBool ());
    }
  catch (const JsonRpc::RpcError& exc)
    {
      // Malformed base64?
      if (exc.getErrorCode () == -5)
        return false;
      throw exc;
    }
}
int
main ()
{
  RpcSettings settings;
  settings.readDefaultConfig ();
  JsonRpc rpc(settings);

  JsonRpc::JsonData res = rpc.executeRpc ("getinfo");
  assert (res.isObject ());
  std::cout << "Running version: " << res["version"].asInt () << std::endl;

  res = rpc.executeRpc ("name_show", "id/domob");
  assert (res.isObject ());
  assert (res["name"].asString () == "id/domob");
  assert (res["value"].isString ());
  assert (res["expires_in"].isInt ());

  try
    {
      rpc.executeRpc ("method-does-not-exist", 5, "");
      assert (false);
    }
  catch (const JsonRpc::RpcError& err)
    {
      assert (err.getErrorCode () == -32601);
    }

  try
    {
      rpc.executeRpc ("name_history", "name-does-not-exist");
      assert (false);
    }
  catch (const JsonRpc::RpcError& err)
    {
      assert (err.getErrorCode () == -4);
    }

  return EXIT_SUCCESS;
}
/**
 * Create a new address (as per "getnewaddress") and return it.
 * @return Newly created address.
 */
CoinInterface::Address
CoinInterface::createAddress ()
{
  const JsonRpc::JsonData addr = rpc.executeRpc ("getnewaddress");
  return Address (rpc, addr.asString ());
}