Skip to content

Commit

Permalink
Add TWFIOAccount (trustwallet#940)
Browse files Browse the repository at this point in the history
* Add TWFIOAccount
* Move regex into Actor.cpp, add android test
  • Loading branch information
hewigovens authored Apr 30, 2020
1 parent 02eab8a commit be69646
Show file tree
Hide file tree
Showing 14 changed files with 242 additions and 57 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ apply plugin: 'kotlin-android'

android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
ndkVersion '21.1.6352462'
defaultConfig {
applicationId "com.trustwallet.core.app"
minSdkVersion 23
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.trustwallet.core.app.blockchains.fio
import com.trustwallet.core.app.utils.toHex
import com.trustwallet.core.app.utils.toHexByteArray
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import wallet.core.jni.*

Expand All @@ -28,4 +29,23 @@ class TestFIOAddress {
val addressFromKey = AnyAddress(pubkey, CoinType.FIO)
assertEquals(addressFromKey.description(), "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o")
}

@Test
fun testAccount() {
assertEquals(FIOAccount("FIO7uMZoeei5HtXAD24C4yCkpWWbf24bjYtrRNjWdmGCXHZccwuiE").description(), "hhq2g4qgycfb")
assertEquals(FIOAccount("hhq2g4qgycfb").description(), "hhq2g4qgycfb")
assertEquals(FIOAccount("rewards@wallet").description(), "rewards@wallet")

var account: FIOAccount? = null
var account2: FIOAccount? = null
try {
account = FIOAccount("asdf19s")
account2 = FIOAccount("0x320196ef1b137786be51aa391e78e0a2c756f46b")
} catch (ex: Exception) {
print(ex)
}

assertNull(account)
assertNull(account2)
}
}
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
classpath 'com.android.tools.build:gradle:3.6.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
Expand Down
28 changes: 28 additions & 0 deletions include/TrustWalletCore/TWFIOAccount.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright © 2017-2020 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 "TWString.h"

TW_EXTERN_C_BEGIN

/// Represents a FIO Account name
TW_EXPORT_CLASS
struct TWFIOAccount;

TW_EXPORT_STATIC_METHOD
struct TWFIOAccount *_Nullable TWFIOAccountCreateWithString(TWString *_Nonnull string);

TW_EXPORT_METHOD
void TWFIOAccountDelete(struct TWFIOAccount *_Nonnull account);

/// Returns the short account string representation.
TW_EXPORT_PROPERTY
TWString *_Nonnull TWFIOAccountDescription(struct TWFIOAccount *_Nonnull account);

TW_EXTERN_C_END
2 changes: 1 addition & 1 deletion src/Cardano/AddressV3.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class AddressV3 {
Data data() const;

private:
AddressV3() : legacyAddressV2(nullptr), discrimination(Discrim_Production), kind(Kind_Single) {}
AddressV3() : discrimination(Discrim_Production), kind(Kind_Single), legacyAddressV2(nullptr) {}
};

inline bool operator==(const AddressV3& lhs, const AddressV3& rhs) {
Expand Down
60 changes: 60 additions & 0 deletions src/FIO/Actor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright © 2017-2020 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 "Actor.h"

#include <regex>

using namespace TW::FIO;
using namespace std;

string Actor::actor(const Address& addr)
{
uint64_t shortenedKey = shortenKey(addr.bytes);
string name13 = name(shortenedKey);
// trim to 12 chracters
return name13.substr(0, 12);
}

bool Actor::validate(const std::string& addr) {
regex pattern(R"(\b([a-z1-5]{3,})[.@]?\b)");
smatch match;
return regex_search(addr, match, pattern);
}

uint64_t Actor::shortenKey(const array<byte, Address::size>& addrKey)
{
uint64_t res = 0;
int i = 1; // Ignore key head
int len = 0;
while (len <= 12) {
assert(i < 33); // Means the key has > 20 bytes with trailing zeroes...

auto trimmed_char = uint64_t(addrKey[i] & (len == 12 ? 0x0f : 0x1f));
if (trimmed_char == 0) { i++; continue; } // Skip a zero and move to next

auto shuffle = len == 12 ? 0 : 5 * (12 - len) - 1;
res |= trimmed_char << shuffle;

len++; i++;
}
return res;
}

string Actor::name(uint64_t shortKey) {
static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";

string str(13,'.'); //We are forcing the string to be 13 characters

uint64_t tmp = shortKey;
for(uint32_t i = 0; i <= 12; i++ ) {
char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)];
str[12 - i] = c;
tmp >>= (i == 0 ? 4 : 5);
}

return str;
}
27 changes: 27 additions & 0 deletions src/FIO/Actor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright © 2017-2020 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 <string>

namespace TW::FIO {
/// Helper class for Actor name generation from address
class Actor {
public:
/// Generate the actor name of the address
static std::string actor(const Address& addr);

/// Check if the address is valid
static bool validate(const std::string& addr);

/// Used internally, derive shortened uint64 key from adddr bytes
static uint64_t shortenKey(const std::array<byte, Address::size>& addrKey);
/// Used internally, derive name from uint64 shortened key
static std::string name(uint64_t shortKey);
};
} // namespace TW::FIO
43 changes: 1 addition & 42 deletions src/FIO/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "Signer.h"
#include "Address.h"
#include "Actor.h"

#include "../Base58.h"
#include "../Hash.h"
Expand Down Expand Up @@ -61,46 +62,4 @@ int Signer::isCanonical(uint8_t by, uint8_t sig[64]) {
&& !(sig[32] == 0 && !(sig[33] & 0x80));
}

string Actor::actor(const Address& addr)
{
uint64_t shortenedKey = shortenKey(addr.bytes);
string name13 = name(shortenedKey);
// trim to 12 chracters
return name13.substr(0, 12);
}

uint64_t Actor::shortenKey(const array<byte, Address::size>& addrKey)
{
uint64_t res = 0;
int i = 1; // Ignore key head
int len = 0;
while (len <= 12) {
assert(i < 33); // Means the key has > 20 bytes with trailing zeroes...

auto trimmed_char = uint64_t(addrKey[i] & (len == 12 ? 0x0f : 0x1f));
if (trimmed_char == 0) { i++; continue; } // Skip a zero and move to next

auto shuffle = len == 12 ? 0 : 5 * (12 - len) - 1;
res |= trimmed_char << shuffle;

len++; i++;
}
return res;
}

string Actor::name(uint64_t shortKey) {
static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";

string str(13,'.'); //We are forcing the string to be 13 characters

uint64_t tmp = shortKey;
for(uint32_t i = 0; i <= 12; i++ ) {
char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)];
str[12 - i] = c;
tmp >>= (i == 0 ? 4 : 5);
}

return str;
}

} // namespace TW::FIO
12 changes: 0 additions & 12 deletions src/FIO/Signer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,4 @@ class Signer {
static int isCanonical(uint8_t by, uint8_t sig[64]);
};

/// Helper class for Actor name generation from address
class Actor {
public:
/// Generate the actor name of the address
static std::string actor(const Address& addr);

/// Used internally, derive shortened uint64 key from adddr bytes
static uint64_t shortenKey(const std::array<byte, Address::size>& addrKey);
/// Used internally, derive name from uint64 shortened key
static std::string name(uint64_t shortKey);
};

} // namespace TW::FIO
1 change: 1 addition & 0 deletions src/FIO/TransactionBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "TransactionBuilder.h"

#include "Actor.h"
#include "Encryption.h"
#include "NewFundsRequest.h"
#include "Signer.h"
Expand Down
39 changes: 39 additions & 0 deletions src/interface/TWFIOAccount.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright © 2017-2020 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 <TrustWalletCore/TWFIOAccount.h>

#include "FIO/Actor.h"
#include "FIO/Address.h"

#include <string>

using namespace TW;
using namespace TW::FIO;

struct TWFIOAccount {
std::string description;
};

struct TWFIOAccount *_Nullable TWFIOAccountCreateWithString(TWString *_Nonnull string) {
const auto& account = *reinterpret_cast<const std::string*>(string);
if (Address::isValid(account)) {
const auto addr = Address(account);
return new TWFIOAccount{Actor::actor(addr)};
}
if (Actor::validate(account)) {
return new TWFIOAccount{account};
}
return nullptr;
}

void TWFIOAccountDelete(struct TWFIOAccount *_Nonnull account) {
delete account;
}

TWString *_Nonnull TWFIOAccountDescription(struct TWFIOAccount *_Nonnull account) {
return TWStringCreateWithUTF8Bytes(account->description.c_str());
}
16 changes: 16 additions & 0 deletions swift/Tests/Blockchains/FIOTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,20 @@ class FIOTests: XCTestCase {

XCTAssertEqual(out.json, expectedJson)
}

func testAccountNames() {
XCTAssertEqual(
FIOAccount(string: "FIO7uMZoeei5HtXAD24C4yCkpWWbf24bjYtrRNjWdmGCXHZccwuiE")!.description, "hhq2g4qgycfb"
)
XCTAssertEqual(
FIOAccount(string: "hhq2g4qgycfb")!.description, "hhq2g4qgycfb"
)

XCTAssertEqual(
FIOAccount(string: "rewards@wallet")!.description, "rewards@wallet"
)

XCTAssertNil(FIOAccount(string: "asdf19s"))
XCTAssertNil(FIOAccount(string: "0x320196ef1b137786be51aa391e78e0a2c756f46b"))
}
}
1 change: 1 addition & 0 deletions tests/FIO/SignerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#include "FIO/Actor.h"
#include "FIO/Signer.h"

#include "HexCoding.h"
Expand Down
46 changes: 46 additions & 0 deletions tests/FIO/TWFIOAccountTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright © 2017-2020 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 "../interface/TWTestUtilities.h"
#include <TrustWalletCore/TWFIOAccount.h>

#include <gtest/gtest.h>

TEST(TWFIO, Account) {
{
auto string = STRING("FIO6XKiobBGrmPZDaHne47TF25CamjFc3cRe8hs7oAiCN59TbJzes");
auto account = TWFIOAccountCreateWithString(string.get());
auto description = WRAPS(TWFIOAccountDescription(account));
assertStringsEqual(description, "rpxtnpsr3gxd");
TWFIOAccountDelete(account);
}

{
auto account = TWFIOAccountCreateWithString(STRING("lhp1ytjibtea").get());
auto account2 = TWFIOAccountCreateWithString(STRING("wrcjejslfplp").get());
auto account3 = TWFIOAccountCreateWithString(STRING("rewards@wallet").get());
auto description = WRAPS(TWFIOAccountDescription(account));
auto description2 = WRAPS(TWFIOAccountDescription(account2));
auto description3 = WRAPS(TWFIOAccountDescription(account3));
assertStringsEqual(description, "lhp1ytjibtea");
assertStringsEqual(description2, "wrcjejslfplp");
assertStringsEqual(description3, "rewards@wallet");

TWFIOAccountDelete(account);
TWFIOAccountDelete(account2);
TWFIOAccountDelete(account3);
}

{
auto string = STRING("asdf19s");
auto string2 = STRING("0x320196ef1b137786be51aa391e78e0a2c756f46b");
auto account = TWFIOAccountCreateWithString(string.get());
auto account2 = TWFIOAccountCreateWithString(string2.get());

ASSERT_EQ(account, nullptr);
ASSERT_EQ(account2, nullptr);
}
}

0 comments on commit be69646

Please sign in to comment.