Наступает эпоха Web3. Скоро во многих сервисах рядом с Mastercard/Visa появятся такие пункты, как USDT, USDC, BUSD и т. д. Как вы возможно уже догадались, речь пойдет о криптовалютах. Все эти койны являются эквивалентны американскому доллару. Главное, что нужно знать о них, это то, что они не управляются одной компанией, а все кошельки и транзакции распределены сетью серверов. Из плюсов-невозможность заблокировать средства на счету и доступ по всему земному шару, где есть интернет.

Для начала обоснуем выбор сети и какую именно валюту мы хотим внедрить. Мой выбор пал на TRON USDT по нескольким причинам:

  1. Он популярен и у вас не возникнет вопросов, как превратить его в реальные деньги.

  2. Низкие комиссии на блокчейне (~0.2$) и при выводе с криптобирж

Первое: нужно скачать Defi кошелек, например, TrustWallet. Он поможет сгенерировать секретную seed фразу, которая используется для получения секретных ключей для любого блокчейна. После регистрации и сохранения seed фразы нужно найти адрес вашего Tron кошелька в таком формате TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t.

Комиссии платятся токеном TRX. Покупаем с карты минимальное количество USDT и TRX. Самый быстрый способ это сделать-через bestchange.ru.

Поехали кодить. Tron Usdt существует в виде смарт контракта, который называется TRC20. Контрактом называют программный код на языке solidity, который говорит, как будет происходить перевод от одного кошелька к другому и определяет интерфейс для перевода. По контракту TRC20 работает не только USDT, а также другие монеты. Так что автоматом вы можете принимать много других монет, которые работают на TRC20.

Последовательность наших действий:

Последовательность наших действий:

  1. Сгенерировать публичный и приватный ключ из seed фразы

  2. Сгенерировать адрес кошелька из приватного ключа

  3. Создать транзакцию

  4. Подписать транзакцию

  5. Отправить подписанную транзакцию в сеть

Всё будем Всё будем делать на Java. Я буду использовать Android, чтобы у меня был отдельный девайс, который выполнял бы все транзакции, и я не светил приватные ключи на чужом хостинге.

Генерируем публичный приватный ключ с помощью bitcoinj и фразы, которую мы сгенерировали в кошельке.

dependencies {    
  implementation 'org.bitcoinj:bitcoinj-core:0.15.9'
}
SDeterministicKey generateKeys(String mnemonic) {
    byte[] seed = MnemonicCode.toSeed(Arrays.asList(mnemonic.split(" ")), "");
    DeterministicKey masterPrivateKey = HDKeyDerivation.createMasterPrivateKey(seed);
    DeterministicHierarchy dh = new DeterministicHierarchy(masterPrivateKey);
    String TRON_DERIVATION_PATH = "M/44H/195H/0H/0";
    List<ChildNumber> path = HDUtils.parsePath(TRON_DERIVATION_PATH);
    int depth = path.size() - 1;
    DeterministicKey startWallet = dh.deriveChild(path.subList(0, depth), false, true, path.get(depth));
    DeterministicKey firstWallet = HDKeyDerivation.deriveChildKey(startWallet, new ChildNumber(0));
    return firstWallet;
}
String mnemonic = "quote enemy figure clog project logic dismiss train wing shoe cement tribe";
DeterministicKey wallet = generateKeys(mnemonic);
String privKeyStr = wallet.getPrivateKeyAsHex();
// 8296345bd446198a4a3f10a91b0ebbfe6a327e52ca14bcdb3ce2ff6e2e37a6f5
String publicKey = wallet.getPublicKeyAsHex();
// 03f0d4462517b3c6512d3b0f5f83e698cd9eb512f364cebc3cc51e6fc988ddf974

Далее из публичного ключа генерируем адрес.

public static byte[] sha256(byte[] input) {
    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(input);
        return digest.digest();
    } catch (NoSuchAlgorithmException var1) {
        throw new RuntimeException(var1);
    }
}

public static byte[] sha3(byte[] input) {
    Keccak.DigestKeccak kecc = new Keccak.Digest256();
    kecc.update(input);
    return kecc.digest();
}

private static String public2Address(byte[] publicKey) {
    byte[] hash = sha3(copyOfRange(publicKey, 1, publicKey.length));
    byte[] address = copyOfRange(hash, 11, hash.length);
    address[0] = 65; // T symbol
    byte[] salt = sha256(sha256(address));
    byte[] inputCheck = new byte[address.length + 4];
    System.arraycopy(address, 0, inputCheck, 0, address.length);
    System.arraycopy(salt, 0, inputCheck, address.length, 4);
    return Base58.encode(inputCheck);
}

String address = public2Address(wallet.getPubKeyPoint().getEncoded(false));
// TYTuGuNJsyb2YEvvQPuG53eqJogArdYCUt

Сверяем адрес публичный и приватный ключи на сайте https://iancoleman.io/bip39/

Создаем транзакцию по документации.

Для этого нам нужно создать параметры в формате Abi.

String prepareParameter(String address, double amountUsdt) {
    byte[] addressBytes = Base58.decode(address);
    addressBytes = Arrays.copyOfRange(addressBytes, 1, 21);
    byte[] amountBytes = BigDecimal.valueOf(amountUsdt)
            .multiply(BigDecimal.valueOf(1000000)).toBigInteger().toByteArray();
    return dataToAbi(addressBytes) + dataToAbi(amountBytes);
}

String dataToAbi(byte[] bytes) {
    byte[] result = new byte[32];
    System.arraycopy(bytes, 0, result, 32 - bytes.length, bytes.length);
    return hex(result);
}

String parameter = prepareParameter(address, 0.01);
// 000000000000000000000000F6C0085430DBA6465BA81FC0E4317EC8EDD02EF10000000000000000000000000000000000000000000000000000000000002710

Делаем запрос.

POST https://api.trongrid.io/wallet/triggersmartcontract

{
     "owner_address": "[YOUR_ADDRESS]",
     "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", //адрес USDT контракта
     "function_selector": "transfer(address,uint256)",
     "call_value": 0,
     "visible": true,
     "parameter": "[YOUR_ABI_PARAMETER]",
     "fee_limit": 100000000
}

Подписываем идентификатор транзакции(txID) с помощью Tronj

String signTransaction(String txId, String privateKeyStr) {
    Bytes32 private32 = Bytes32.fromHexString(privateKeyStr);
    SECP256K1.PrivateKey privateKey = SECP256K1.PrivateKey.create(private32);
    SECP256K1.KeyPair keyPair = SECP256K1.KeyPair.create(privateKey);
    Bytes32 trId32 = Bytes32.wrap(Hex.decode(txId.getBytes()));
    SECP256K1.Signature sig = SECP256K1.sign(trId32, keyPair);
    return hex(sig.encodedBytes().toArray());
}

String signature = signTransaction("[YOUR_TXID]", privKeyStr);
// 475F30E3BC3CAD690ABCD55480D81FA7423001D2A1ED9463D81BF65BE4A2F8563217026ADA12AE8F5225B9D3763CCDBCDD0D1352EB658831E174F8ADF5DA127B00

Отсылаем транзакцию в сеть по документации.

POST https://api.trongrid.io/wallet/broadcasttransaction

{
    // Полностью копируем транзакцию из предыдущего ответа
    "signature":["[YOUR_SIGNATURE]"] // и добавляем сигнатуру
}

Проверяем транзакцию через https://tronscan.org/

P.S. Так как я очень не люблю использовать зависимости в проекте, я постараюсь выделить подпись транзакции в маленький понятный код без использования Tronj.

Комментарии (3)


  1. beatleboy
    11.10.2022 17:49
    +5

    Сверяем адрес публичный и приватный ключи на сайте https://iancoleman.io/bip39/

    Для безопасности советую не вводить свои сид фразы, приватники на сторонние веб-сервисы.
    Все это может утечь и попасть к злоумышленникам в руки. Как итог лишитесь денег.


  1. dmitryvolochaev
    11.10.2022 18:37
    +2

    С технической стороны очень интересно. Разобрали отправку транзакции. Хотелось бы еще узнать, как проверять, пришел ли платеж вам.

    Но вот по политико-экономической части есть замечания.

    рядом с Mastercard/Visa появятся такие пункты, как USDT, USDC, BUSD

    Вы новости читаете? ЦБ собирается запретить крипту, а в Европе запретят крипту для нас. Переводы между некастодиальными кошельками останутся, да.

    не управляются одной компанией

    USDT и BUSD управляются разными компаниями. Но и Tether, и Binance могут как банить отдельные кошельки, так и полностью останавливать блокчейн на время рыночного хаоса.

    Самый быстрый способ это сделать-через bestchange.ru.

    То, что быстрый, не спорю. А вы курс видели? Может, стоит рассмотреть p2p-обмен?

    Делаем запрос

    Запрос к какому-то сайту, от которого и зависит, попадет ли транзакция в блокчейн. Секретный ключ мы этому сайту не доверяем. Это уже хорошо. Но полноценный web3 - это когда у тебя на компе свой узел p2p-сети, который синхронизирует блокчейн и отправляет транзакции в сеть.


    1. mapcuk
      11.10.2022 22:01

      Не уверен, что Tether остановит, например Ethereum. А Binance прям недавно смогла

      Биржа Binance попросила валидаторов остановить производство блоков в сети Binance Smart Chain, после того как хакеры воспользовались уязвимостью в межсетевом мосте BSC Token Hub и вывели активов на $586 млн.