Skip to content

Commit

Permalink
Sync dev with master (#3358)
Browse files Browse the repository at this point in the history
* [NewChain/Base]: add base blockchain (#3342)

* [Aptos]: Add `transfer_coins` function call (#3344)

* feat(aptos): Add `TokenTransferCoinsMessage` to call `aptos_account::transfer_coins` function

* Add test with testnet transaction

* feat(aptos): Add mainnet test

* feat(aptos): Fix comment

* [Bitcoin] Fix `TWBitcoinFeeCalculateFee` (for JavaScript) (#3346)

* [Barz] Allow deriving multiple addresses from a single public key (#3340)

* [Barz] Allow deriving multiple addresses from a single public key

* fix tests

* Update BarzTests.swift

* update tests

* update tests

* update tests

* [ETH]: Handle `tuple[]` ABI type parameter (#3352)

---------

Co-authored-by: Sztergbaum Roman <rmscastle@gmail.com>
Co-authored-by: Fabio Lama <42901763+lamafab@users.noreply.github.com>
Co-authored-by: Ruslan Serebriakov <rsrbk@users.noreply.github.com>
  • Loading branch information
4 people authored Aug 11, 2023
1 parent 89e20ec commit 7a22f89
Show file tree
Hide file tree
Showing 44 changed files with 885 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class CoinAddressDerivationTests {
ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ZKSYNC, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI,
FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS,
AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER, OKXCHAIN, POLYGONZKEVM, SCROLL,
CONFLUXESPACE, ACALAEVM, OPBNBTESTNET, NEON -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address)
CONFLUXESPACE, ACALAEVM, OPBNBTESTNET, NEON, BASE -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address)
RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address)
ETHEREUMCLASSIC -> assertEquals("0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c", address)
GOCHAIN -> assertEquals("0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2", address)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,47 @@ class TestAptosSigner {
"07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01"
)
}

@Test
fun AptosTransferTokensCoins() {
// Successfully broadcasted https://explorer.aptoslabs.com/txn/0x197d40ea12e2bfc65a0a913b9f4ca3b0b0208fe0c1514d3d55cef3d5bcf25211?network=mainnet
val key =
"e7f56c77189e03699a75d8ec5c090e41f3d9d4783bc49c33df8a93d915e10de8".toHexBytesInByteString()

val function = Aptos.StructTag.newBuilder()
.setAccountAddress("0xe9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9")
.setModule("mee_coin")
.setName("MeeCoin")
.build()

val transfer = Aptos.TokenTransferCoinsMessage.newBuilder()
.setAmount(10000)
.setTo("0xb7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c")
.setFunction(function)
.build()
val signingInput = Aptos.SigningInput.newBuilder()
.setChainId(1)
.setSender("0x1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf25")
.setSequenceNumber(2)
.setGasUnitPrice(100)
.setMaxGasAmount(2000)
.setExpirationTimestampSecs(3664390082)
.setTokenTransferCoins(transfer)
.setPrivateKey(key)
.build()

val result = AnySigner.sign(signingInput, CoinType.APTOS, Aptos.SigningOutput.parser())
assertEquals(
Numeric.cleanHexPrefix(Numeric.toHexString(result.rawTxn.toByteArray())),
"1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf2502000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e7472616e736665725f636f696e730107e9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9086d65655f636f696e074d6565436f696e000220b7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c081027000000000000d0070000000000006400000000000000c2276ada0000000001"
)
assertEquals(
Numeric.cleanHexPrefix(Numeric.toHexString(result.authenticator.signature.toByteArray())),
"30ebd7e95cb464677f411868e2cbfcb22bc01cc63cded36c459dff45e6d2f1354ae4e090e7dfbb509851c0368b343e0e5ecaf6b08e7c1b94c186530b0f7dee0d"
)
assertEquals(
Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())),
"1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf2502000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e7472616e736665725f636f696e730107e9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9086d65655f636f696e074d6565436f696e000220b7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c081027000000000000d0070000000000006400000000000000c2276ada0000000001002062e7a6a486553b56a53e89dfae3f780693e537e5b0a7ed33290780e581ca83694030ebd7e95cb464677f411868e2cbfcb22bc01cc63cded36c459dff45e6d2f1354ae4e090e7dfbb509851c0368b343e0e5ecaf6b08e7c1b94c186530b0f7dee0d"
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ class TestBitcoinFee {

@Test
fun P2pkhCalculateFee() {
val satVb: Long = 10
val satVb = "10"
val tx = Numeric.hexStringToByteArray("02000000017be4e642bb278018ab12277de9427773ad1c5f5b1d164a157e0d99aa48dc1c1e000000006a473044022078eda020d4b86fcb3af78ef919912e6d79b81164dbbb0b0b96da6ac58a2de4b102201a5fd8d48734d5a02371c4b5ee551a69dca3842edbf577d863cf8ae9fdbbd4590121036666dd712e05a487916384bfcd5973eb53e8038eccbbf97f7eed775b87389536ffffffff01c0aff629010000001976a9145eaaa4f458f9158f86afcba08dd7448d27045e3d88ac00000000")
var fee = BitcoinFee.calculateFee(tx, satVb)
var fee = BitcoinFee.calculateFee(tx, satVb).toLong()

assertEquals(fee, 191 * satVb)
assertEquals(fee, 191 * satVb.toLong())
}

@Test
fun P2wpkhCalculateFee() {
val satVb: Long = 12
val satVb = "12"
val tx = Numeric.hexStringToByteArray("020000000111b9f62923af73e297abb69f749e7a1aa2735fbdfd32ac5f6aa89e5c96841c18000000006b483045022100df9ed0b662b759e68b89a42e7144cddf787782a7129d4df05642dd825930e6e6022051a08f577f11cc7390684bbad2951a6374072253ffcf2468d14035ed0d8cd6490121028d7dce6d72fb8f7af9566616c6436349c67ad379f2404dd66fe7085fe0fba28fffffffff01c0aff629010000001600140d0e1cec6c2babe8badde5e9b3dea667da90036d00000000")
var fee = BitcoinFee.calculateFee(tx, satVb)
var fee = BitcoinFee.calculateFee(tx, satVb).toLong()

assertEquals(fee, 189 * satVb)
assertEquals(fee, 189 * satVb.toLong())
}

@Test
Expand All @@ -38,10 +38,10 @@ class TestBitcoinFee {
// Size 235 Bytes
// Weight 610
fun Brc20TransferCommitCalculateFee() {
val satVb: Long = 19
val satVb = "19"
val tx = Numeric.hexStringToByteArray("02000000000101089098890d2653567b9e8df2d1fbe5c3c8bf1910ca7184e301db0ad3b495c88e0100000000ffffffff02581b000000000000225120e8b706a97732e705e22ae7710703e7f589ed13c636324461afa443016134cc051040000000000000160014e311b8d6ddff856ce8e9a4e03bc6d4fe5050a83d02483045022100a44aa28446a9a886b378a4a65e32ad9a3108870bd725dc6105160bed4f317097022069e9de36422e4ce2e42b39884aa5f626f8f94194d1013007d5a1ea9220a06dce0121030f209b6ada5edb42c77fd2bc64ad650ae38314c8f451f3e36d80bc8e26f132cb00000000")
var fee = BitcoinFee.calculateFee(tx, satVb)
var fee = BitcoinFee.calculateFee(tx, satVb).toLong()

assertEquals(fee, 153 * satVb) // 153 = ceil(610/4)
assertEquals(fee, 153 * satVb.toLong()) // 153 = ceil(610/4)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,21 @@ class TestBarz {
val publicKeyData = Numeric.hexStringToByteArray("04e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b02")
val publicKey = PublicKey(publicKeyData, PublicKeyType.NIST256P1EXTENDED)
val verificationFacet = "0x6BF22ff186CC97D88ECfbA47d1473a234CEBEFDf"
val result = WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet)
val result = WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet, 0)
assertEquals(Numeric.toHexString(result), "0x3fc708630d85a3b5ec217e53100ec2b735d4f800296601cd0000000000000000000000006bf22ff186cc97d88ecfba47d1473a234cebefdf00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004104e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b0200000000000000000000000000000000000000000000000000000000000000")
}

@Test
fun testInitCodeNonZeroSalt() {
val factoryAddress = "0x3fC708630d85A3B5ec217E53100eC2b735d4f800"
val publicKeyData = Numeric.hexStringToByteArray("04e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b02")
val publicKey = PublicKey(publicKeyData, PublicKeyType.NIST256P1EXTENDED)
val verificationFacet = "0x6BF22ff186CC97D88ECfbA47d1473a234CEBEFDf"
val salt = 1
val result = WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet, salt)
assertEquals(Numeric.toHexString(result), "0x3fc708630d85a3b5ec217e53100ec2b735d4f800296601cd0000000000000000000000006bf22ff186cc97d88ecfba47d1473a234cebefdf00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004104e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b0200000000000000000000000000000000000000000000000000000000000000")
}

@Test
fun testCounterfactualAddress() {
val input = Barz.ContractAddressInput.newBuilder()
Expand All @@ -55,6 +66,24 @@ class TestBarz {
assertEquals(result, "0x77F62bb3E43190253D4E198199356CD2b25063cA")
}

@Test
fun testCounterfactualAddressNonZeroSalt() {
val input = Barz.ContractAddressInput.newBuilder()
input.apply {
factory = "0x96C489979E39F877BDb8637b75A25C1a5B2DE14C"
accountFacet = "0xF6F5e5fC74905e65e3FF53c6BacEba8535dd14d1"
verificationFacet = "0xaB84813cbf26Fd951CB3d7E33Dccb8995027e490"
entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
facetRegistry = "0x9a95d201BB8F559771784D12c01F8084278c65E5"
defaultFallback = "0x522cDc7558b5f798dF5D61AB09B6D95Ebd342EF9"
bytecode = "0x60806040526040516104c83803806104c883398101604081905261002291610163565b6000858585858560405160240161003d959493929190610264565b60408051601f198184030181529181526020820180516001600160e01b0316634a93641760e01b1790525190915060009081906001600160a01b038a16906100869085906102c3565b600060405180830381855af49150503d80600081146100c1576040519150601f19603f3d011682016040523d82523d6000602084013e6100c6565b606091505b50915091508115806100e157506100dc816102df565b600114155b156100ff57604051636ff35f8960e01b815260040160405180910390fd5b505050505050505050610306565b80516001600160a01b038116811461012457600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561015a578181015183820152602001610142565b50506000910152565b60008060008060008060c0878903121561017c57600080fd5b6101858761010d565b95506101936020880161010d565b94506101a16040880161010d565b93506101af6060880161010d565b92506101bd6080880161010d565b60a08801519092506001600160401b03808211156101da57600080fd5b818901915089601f8301126101ee57600080fd5b81518181111561020057610200610129565b604051601f8201601f19908116603f0116810190838211818310171561022857610228610129565b816040528281528c602084870101111561024157600080fd5b61025283602083016020880161013f565b80955050505050509295509295509295565b600060018060a01b0380881683528087166020840152808616604084015280851660608401525060a0608083015282518060a08401526102ab8160c085016020870161013f565b601f01601f19169190910160c0019695505050505050565b600082516102d581846020870161013f565b9190910192915050565b80516020808301519190811015610300576000198160200360031b1b821691505b50919050565b6101b3806103156000396000f3fe60806040523661000b57005b600080356001600160e01b03191681527f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f6020819052604090912054819060601c806100cf576004838101546040516366ffd66360e11b81526000356001600160e01b031916928101929092526001600160a01b03169063cdffacc690602401602060405180830381865afa1580156100a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100cc919061014d565b90505b6001600160a01b0381166101295760405162461bcd60e51b815260206004820152601d60248201527f4261727a3a2046756e6374696f6e20646f6573206e6f74206578697374000000604482015260640160405180910390fd5b3660008037600080366000845af43d6000803e808015610148573d6000f35b3d6000fd5b60006020828403121561015f57600080fd5b81516001600160a01b038116811461017657600080fd5b939250505056fea2646970667358221220d35db061bb6ecdb7688c3674af669ce44d527cae4ded59214d06722d73da62be64736f6c63430008120033"
publicKey = "0xB5547FBdC56DCE45e1B8ef75569916D438e09c46"
salt = 123456
}
val result = WCBarz.getCounterfactualAddress(input.build().toByteArray())
assertEquals(result, "0xB91aaa96B138A1B1D94c9df4628187132c5F2bf1")
}

@Test
fun testGetFormattedSignature() {
val signature = Numeric.hexStringToByteArray("0x3044022012d89e3b41e253dc9e90bd34dc1750d059b76d0b1d16af2059aa26e90b8960bf0220256d8a05572c654906ce422464693e280e243e6d9dbc5f96a681dba846bca276")
Expand Down Expand Up @@ -126,7 +155,7 @@ class TestBarz {
sender = "0x1392Ae041BfBdBAA0cFF9234a0C8F64df97B7218"
preVerificationGas = ByteString.copyFrom("0xb708".toHexByteArray())
verificationGasLimit = ByteString.copyFrom("0x2DC6C0".toHexByteArray())
initCode = ByteString.copyFrom(WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet))
initCode = ByteString.copyFrom(WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet, 0))
}.build()

transaction = Ethereum.Transaction.newBuilder().apply {
Expand Down
1 change: 1 addition & 0 deletions docs/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ This list is generated from [./registry.json](../registry.json)
| 3030 | Hedera | HBAR | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/hedera/info/logo.png" width="32" /> | <https://hedera.com/> |
| 5611 | OpBNB testnet | tBNB | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/opbnb/info/logo.png" width="32" /> | <https://opbnb.bnbchain.org/en> |
| 6060 | GoChain | GO | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/gochain/info/logo.png" width="32" /> | <https://gochain.io> |
| 8453 | Base | ETH | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/base/info/logo.png" width="32" /> | <https://base.mirror.xyz/> |
| 8964 | NULS | NULS | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/nuls/info/logo.png" width="32" /> | <https://nuls.io> |
| 14001 | WAX | WAXP | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/wax/info/logo.png" width="32" /> | <http://wax.io> |
| 18000 | Meter | MTR | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/meter/info/logo.png" width="32" /> | <https://meter.io/> |
Expand Down
2 changes: 1 addition & 1 deletion include/TrustWalletCore/TWBarz.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ TWString *_Nonnull TWBarzGetCounterfactualAddress(TWData *_Nonnull input);
/// \param verificationFacet Verification facet address
/// \return The address.
TW_EXPORT_STATIC_METHOD
TWData *_Nonnull TWBarzGetInitCode(TWString* _Nonnull factory, struct TWPublicKey* _Nonnull publicKey, TWString* _Nonnull verificationFacet);
TWData *_Nonnull TWBarzGetInitCode(TWString* _Nonnull factory, struct TWPublicKey* _Nonnull publicKey, TWString* _Nonnull verificationFacet, uint32_t salt);

/// Converts the original ASN-encoded signature from webauthn to the format accepted by Barz
///
Expand Down
8 changes: 7 additions & 1 deletion include/TrustWalletCore/TWBitcoinFee.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@
#pragma once

#include "TWData.h"
#include "TWString.h"

TW_EXTERN_C_BEGIN

TW_EXPORT_CLASS
struct TWBitcoinFee;

/// Calculates the fee of any Bitcoin transaction.
///
/// \param data: the signed transaction in its final form.
/// \param satVb: the satoshis per vbyte amount. The passed on string is interpreted as a unit64_t.
/// \returns the fee denominated in satoshis or nullptr if the transaction failed to be decoded.
TW_EXPORT_STATIC_METHOD
uint64_t TWBitcoinFeeCalculateFee(TWData* _Nonnull data, uint64_t satVb);
TWString* _Nullable TWBitcoinFeeCalculateFee(TWData* _Nonnull data, TWString* _Nonnull satVb);

TW_EXTERN_C_END
1 change: 1 addition & 0 deletions include/TrustWalletCore/TWCoinType.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ enum TWCoinType {
TWCoinTypeAcalaEVM = 10000787,
TWCoinTypeOpBNBtestnet = 5611,
TWCoinTypeNeon = 245022934,
TWCoinTypeBase = 8453,
};

/// Returns the blockchain for a coin type.
Expand Down
30 changes: 30 additions & 0 deletions registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,36 @@
"documentation": "https://docs.syscoin.org"
}
},
{
"id": "base",
"name": "Base",
"coinId": 8453,
"symbol": "ETH",
"decimals": 18,
"blockchain": "Ethereum",
"derivation": [
{
"path": "m/44'/60'/0'/0/0"
}
],
"curve": "secp256k1",
"publicKeyType": "secp256k1Extended",
"chainId": "8453",
"addressHasher": "keccak256",
"explorer": {
"url": "https://basescan.org",
"txPath": "/tx/",
"accountPath": "/address/",
"sampleTx": "0x4acb15506b7696a2dfac4258f3f86392b4b2b717a3f316a8aa78509b2c3b6ab4",
"sampleAccount": "0xb8ff877ed78ba520ece21b1de7843a8a57ca47cb"
},
"info": {
"url": "https://base.mirror.xyz/",
"source": "https://github.com/base-org",
"rpc": "https://mainnet.base.org",
"documentation": "https://docs.base.org/"
}
},
{
"id": "ethereum",
"name": "Ethereum",
Expand Down
12 changes: 12 additions & 0 deletions src/Aptos/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ TransactionPayload tokenTransferPayload(const Proto::SigningInput& input) {
return payload;
}

TransactionPayload tokenTransferCoinsPayload(const Proto::SigningInput& input) {
auto&& [args, argsJson] = commonTransferPayload(input.token_transfer_coins());
auto& function = input.token_transfer_coins().function();
TypeTag tokenTransferTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(Address(function.account_address()),
function.module(), function.name(), {})})};
TransactionPayload payload = EntryFunction(gAptosAccountModule, "transfer_coins", {tokenTransferTag}, args, argsJson);
return payload;
}

TransactionPayload registerTokenPayload(const Proto::SigningInput& input) {

auto& function = input.register_token().function();
Expand Down Expand Up @@ -257,6 +266,9 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) {
case Proto::SigningInput::kLiquidStakingMessage: {
return liquidStakingFunctor(input.liquid_staking_message());
}
case Proto::SigningInput::kTokenTransferCoins: {
return tokenTransferCoinsPayload(input);
}
case Proto::SigningInput::TRANSACTION_PAYLOAD_NOT_SET:
throw std::runtime_error("Transaction payload should be set");
}
Expand Down
Loading

0 comments on commit 7a22f89

Please sign in to comment.