Skip to content

Commit

Permalink
Add Ark support (#438)
Browse files Browse the repository at this point in the history
* Ark Implementation

* rebase and cleanup

* Fix explorer url
  • Loading branch information
hewigovens committed May 19, 2019
1 parent ebe041f commit fa22817
Show file tree
Hide file tree
Showing 26 changed files with 653 additions and 2 deletions.
Expand Up @@ -75,5 +75,6 @@ class CoinAddressDerivationTests {
SEMUX -> assertEquals("0xfe604170382452f77bc922bc19eb4b53504b09c2", address)
DEXON -> assertEquals("0x6F3E6a6dDf2C2B4B32B8Bb452eA3F36B2BB489BF", address)
ZELCASH -> assertEquals("t1UKbRPzL4WN8Rs8aZ8RNiWoD2ftCMHKGUf", address)
ARK -> assertEquals("Ac49m5pu5YpMMNgEbSYeZUEpRMHcSK3DfV", address)
}
}
@@ -0,0 +1,32 @@
package com.trustwallet.core.app.blockchains.ark

import com.trustwallet.core.app.utils.toHexBytesInByteString
import junit.framework.Assert.assertEquals
import org.junit.Test
import wallet.core.jni.ARKSigner
import wallet.core.jni.proto.ARK

class TestArkTransactionSigning{
init {
System.loadLibrary("TrustWalletCore")
}
@Test
fun arkTransactionSigning(){
val signingInput = ARK.SigningInput.newBuilder()
.setType(ARK.TransactionType.Transfer)
.setAmount(123123123)
.setPrivateKey("d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712".toHexBytesInByteString())
.setTimestamp(67447770)
.setToAddress("ARkMaRcjcwRgr6vmDtAWo7bFqUgy9wG3NU")
.setFee(10000000)
.build()

val output = ARKSigner.sign(signingInput)

assertEquals(output.signature, "304402205e6365f4c3b49c28f03afd89d308736dca56671ea707dd3dd5af42272a0cc8ed02207fa7fc015fba7ae527d22a058cc4ebd8e9867c563ace7effc2dbaad2af8976c3".toHexBytesInByteString())
assertEquals(output.encoded, "{\"amount\":123123123,\"asset\":{},\"fee\":10000000,\"id\":\"219b1cc99ec804df02230a9e913ccb45edb7819f22328e3cd15030174a8c4167\",\"recipientId\":\"ARkMaRcjcwRgr6vmDtAWo7bFqUgy9wG3NU\",\"senderPublicKey\":\"034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192\",\"signature\":\"304402205e6365f4c3b49c28f03afd89d308736dca56671ea707dd3dd5af42272a0cc8ed02207fa7fc015fba7ae527d22a058cc4ebd8e9867c563ace7effc2dbaad2af8976c3\",\"timestamp\":67447770,\"type\":0}")

}

class Asset
}
11 changes: 11 additions & 0 deletions coins.json
Expand Up @@ -593,5 +593,16 @@
"xpub": "xpub",
"xprv": "xprv",
"explorer": "https://explorer.zel.cash/tx/"
},
{
"id": "ark",
"name": "ARK",
"symbol": "ARK",
"decimals": 8,
"blockchain": "Ark",
"derivationPath": "m/44'/111'/0'/0/0",
"curve": "secp256k1",
"publicKeyType": "secp256k1",
"explorer": "https://explorer.ark.io/transaction/"
}
]
42 changes: 42 additions & 0 deletions include/TrustWalletCore/TWARKAddress.h
@@ -0,0 +1,42 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
#pragma once
#include "TWBase.h"
#include "TWData.h"
#include "TWString.h"

TW_EXTERN_C_BEGIN

struct TWPublicKey;

/// Represents an ARK address.
TW_EXPORT_CLASS
struct TWARKAddress;

/// Compares two addresses for equality.
TW_EXPORT_STATIC_METHOD
bool TWARKAddressEqual(struct TWARKAddress *_Nonnull lhs, struct TWARKAddress *_Nonnull rhs);

/// Determines if the string is a valid address.
TW_EXPORT_STATIC_METHOD
bool TWARKAddressIsValidString(TWString *_Nonnull string);

/// Creates an address from a string representaion.
TW_EXPORT_STATIC_METHOD
struct TWARKAddress *_Nullable TWARKAddressCreateWithString(TWString *_Nonnull string);

/// Creates an address from a public key.
TW_EXPORT_STATIC_METHOD
struct TWARKAddress *_Nonnull TWARKAddressCreateWithPublicKey(struct TWPublicKey *_Nonnull publicKey);

TW_EXPORT_METHOD
void TWARKAddressDelete(struct TWARKAddress *_Nonnull address);

/// Returns the address string representation.
TW_EXPORT_PROPERTY
TWString *_Nonnull TWARKAddressDescription(struct TWARKAddress *_Nonnull address);

TW_EXTERN_C_END
12 changes: 12 additions & 0 deletions include/TrustWalletCore/TWARKProto.h
@@ -0,0 +1,12 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#pragma once

#include "TWData.h"

typedef TWData *_Nonnull TW_ARK_Proto_SigningInput;
typedef TWData *_Nonnull TW_ARK_Proto_SigningOutput;
21 changes: 21 additions & 0 deletions include/TrustWalletCore/TWARKSigner.h
@@ -0,0 +1,21 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
#pragma once

#include "TWBase.h"
#include "TWData.h"
#include "TWARKProto.h"

TW_EXTERN_C_BEGIN

TW_EXPORT_CLASS
struct TWARKSigner;

/// Signs a transaction.
TW_EXPORT_STATIC_METHOD
TW_ARK_Proto_SigningOutput TWARKSignerSign(TW_ARK_Proto_SigningInput input);

TW_EXTERN_C_END
1 change: 1 addition & 0 deletions include/TrustWalletCore/TWBlockchain.h
Expand Up @@ -29,6 +29,7 @@ enum TWBlockchain {
TWBlockchainOntology = 14,
TWBlockchainZilliqa = 15,
TWBlockchainIoTeX = 16,
TWBlockchainArk = 17
};

TW_EXTERN_C_END
1 change: 1 addition & 0 deletions include/TrustWalletCore/TWCoinType.h
Expand Up @@ -70,6 +70,7 @@ enum TWCoinType {
TWCoinTypeSemux = 7562605,
TWCoinTypeDEXON = 237,
TWCoinTypeZelcash = 19167,
TWCoinTypeARK = 111,
};

/// Returns the blockchain for a coin type.
Expand Down
29 changes: 29 additions & 0 deletions js/tests/blockchain/ark/ARKSigner.test.ts
@@ -0,0 +1,29 @@
import { expect } from 'chai';
import 'mocha';

import * as Long from 'long';

import { fromHexString, bufToHex } from '../../Utils';
import { TW, ARKSigner } from '../../../lib';

describe('ARKSigner', () => {

it('test sign ARKSigner', () => {
let privateKey = fromHexString("d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712");

let input = TW.ARK.Proto.SigningInput.create({
type: TW.ARK.Proto.TransactionType.Transfer,
privateKey: privateKey,
amount: Long.fromNumber(123123123),
fee: Long.fromNumber(10000000),
timestamp: 67447770,
toAddress: "ARkMaRcjcwRgr6vmDtAWo7bFqUgy9wG3NU"
});

let output = ARKSigner.sign(input);

expect(bufToHex(output.signature)).to.equal("0x304402205e6365f4c3b49c28f03afd89d308736dca56671ea707dd3dd5af42272a0cc8ed02207fa7fc015fba7ae527d22a058cc4ebd8e9867c563ace7effc2dbaad2af8976c3");
expect(output.encoded).to.equal("{\"amount\":123123123,\"asset\":{},\"fee\":10000000,\"id\":\"219b1cc99ec804df02230a9e913ccb45edb7819f22328e3cd15030174a8c4167\",\"recipientId\":\"ARkMaRcjcwRgr6vmDtAWo7bFqUgy9wG3NU\",\"senderPublicKey\":\"034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192\",\"signature\":\"304402205e6365f4c3b49c28f03afd89d308736dca56671ea707dd3dd5af42272a0cc8ed02207fa7fc015fba7ae527d22a058cc4ebd8e9867c563ace7effc2dbaad2af8976c3\",\"timestamp\":67447770,\"type\":0}");
});

});
21 changes: 21 additions & 0 deletions src/ARK/Address.cpp
@@ -0,0 +1,21 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#include "Address.h"
#include "../Hash.h"
#include "../PublicKey.h"

using namespace TW;
using namespace TW::ARK;

Address::Address(const PublicKey &publicKey) {
if (publicKey.type != TWPublicKeyTypeSECP256k1) {
throw std::invalid_argument("Ark::Address needs a compressed SECP256k1 public key.");
}
const auto data =
publicKey.hash({Address::prefix}, static_cast<Data (*)(const byte*, const byte*)>(Hash::ripemd), false);
std::copy(data.begin(), data.end(), bytes.begin());
}
35 changes: 35 additions & 0 deletions src/ARK/Address.h
@@ -0,0 +1,35 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#pragma once

#include "../Data.h"
#include "../Base58Address.h"
#include "../PublicKey.h"

namespace TW::ARK {

class Address : public TW::Base58Address<21> {
public:
/// mainnet address prefix
static const byte prefix = 0x17;

/// Initializes an address with a string representation.
explicit Address(const std::string& string) : TW::Base58Address<21>(string) {}

/// Initializes an address with a collection of bytes.
explicit Address(const Data& data) : TW::Base58Address<21>(data) {}

/// Initializes an address with a public key and a prefix.
Address(const PublicKey& publicKey);
};

} // namespace TW::ARK

// Wrapper for C interface.
struct TWARKAddress {
TW::ARK::Address impl;
};
24 changes: 24 additions & 0 deletions src/ARK/Signer.cpp
@@ -0,0 +1,24 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#include "Signer.h"
#include "../Hash.h"
#include "../PublicKey.h"

#include <TrustWalletCore/TWPublicKeyType.h>

using namespace TW::ARK;

Proto::SigningOutput Signer::sign(PrivateKey &privateKey, Transaction &tx) {
Data hash = Hash::sha256(tx.encoded());
tx.signature = privateKey.signAsDER(hash, TWCurveSECP256k1);

Proto::SigningOutput output;
output.set_signature(tx.signature.data(), tx.signature.size());
output.set_encoded(tx.encodedJson());

return output;
}
24 changes: 24 additions & 0 deletions src/ARK/Signer.h
@@ -0,0 +1,24 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#pragma once

#include "Transaction.h"
#include "../PrivateKey.h"
#include "../proto/ARK.pb.h"

namespace TW::ARK {
class Signer {
public:
static Proto::SigningOutput sign(PrivateKey &privateKey, Transaction &tx);
};

}; // namespace TW::ARK

// Wrapper for C interface.
struct TWARKSigner {
TW::ARK::Signer impl;
};
54 changes: 54 additions & 0 deletions src/ARK/Transaction.cpp
@@ -0,0 +1,54 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#include "Transaction.h"
#include "../Base58.h"
#include "../BinaryCoding.h"
#include "../Data.h"
#include "../Hash.h"
#include "../HexCoding.h"

#include <nlohmann/json.hpp>

using json = nlohmann::json;

using namespace TW;
using namespace TW::ARK;

Data Transaction::encoded() const {

// transaction type
auto data = Data{type};

encode32LE(timestamp, data);
append(data, publicKey);
append(data, Data(to.bytes.begin(), to.bytes.end()));

// vendor field
Data vendor(64, 0);
append(data, vendor);

encode64LE(amount, data);
encode64LE(fee, data);

if (signature.size() > 0) {
append(data, signature);
}
return data;
}

std::string Transaction::encodedJson() const {
json j = {{"amount", amount},
{"asset", {}},
{"fee", fee},
{"id", hex(Hash::sha256(encoded()))},
{"recipientId", to.string()},
{"senderPublicKey", hex(publicKey)},
{"signature", hex(signature)},
{"timestamp", timestamp},
{"type", type}};
return j.dump();
}
43 changes: 43 additions & 0 deletions src/ARK/Transaction.h
@@ -0,0 +1,43 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#pragma once

#include "Address.h"
#include "../Data.h"

namespace TW::ARK {

class Transaction {
public:
byte type;
uint64_t amount;
uint64_t fee;
uint32_t timestamp;
Address to;
Data publicKey;

/// Transaction signature.
Data signature;

Transaction(byte type, uint64_t amount, uint64_t fee, uint32_t timestamp, Address to,
Data publicKey)
: type(type)
, amount(amount)
, fee(fee)
, timestamp(timestamp)
, to(to)
, publicKey(publicKey) {}

public:
/// Encodes the transaction.
Data encoded() const;

/// Encodes the transaction as json string.
std::string encodedJson() const;
};

} // namespace TW::ARK

0 comments on commit fa22817

Please sign in to comment.