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 <[email protected]>
Co-authored-by: Fabio Lama <[email protected]>
Co-authored-by: Ruslan Serebriakov <[email protected]>
  • Loading branch information
4 people committed Oct 6, 2023
1 parent 0a3ba16 commit a104f8d
Show file tree
Hide file tree
Showing 19 changed files with 185 additions and 41 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 -> 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 @@ -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
2 changes: 2 additions & 0 deletions include/TrustWalletCore/TWCoinType.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ enum TWCoinType {
TWCoinTypeAcala = 787,
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
7 changes: 7 additions & 0 deletions src/Ethereum/ABI/Array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ std::shared_ptr<ParamBase> ParamArray::clone() const {
return newArray;
}

std::shared_ptr<ParamBase> ParamArray::clone() const {
auto newArray = std::make_shared<ParamArray>();
newArray->_params = _params.clone();
newArray->_proto = _proto->clone();
return newArray;
}

void ParamArrayFix::encode(Data& data) const {
this->_params.encode(data);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Ethereum/ABI/Array.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class ParamArray final : public ParamCollection {
bool decode(const Data& encoded, size_t& offset_inout) override;
bool setValueJson(const std::string& value) override;
Data hashStruct() const override;
void fillExtraTypesMap(ExtraTypesMap& extraTypes) const override;
std::string getExtraTypes(std::vector<std::string>& ignoreList) const override;
std::shared_ptr<ParamBase> clone() const override;
};

Expand Down
11 changes: 3 additions & 8 deletions src/Ethereum/ABI/ParamBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,11 @@

#include "Data.h"

#include <map>
#include <memory>
#include <string>
#include <memory>

namespace TW::Ethereum::ABI {

// A map of `StructName -> StructType` key-values, where `StructType` is a full type including the structure name.
// Referenced struct type should be sorted by name see: https://eips.ethereum.org/EIPS/eip-712#definition-of-encodetype
using ExtraTypesMap = std::map<std::string, std::string, std::less<>>;

/// Abstract base class for parameters.
class ParamBase
{
Expand All @@ -31,8 +26,8 @@ class ParamBase
virtual bool setValueJson(const std::string& value) = 0;
// EIP712-style hash of the value (used for signing); default implementation
virtual Data hashStruct() const;
// Helper for EIP712 encoding; fill the given `extraTypes` (recursively).
virtual void fillExtraTypesMap([[maybe_unused]] ExtraTypesMap& extraTypes) const {}
// Helper for EIP712 encoding; provide full type of all used types (recursively). Default is empty implementation.
virtual std::string getExtraTypes([[maybe_unused]] std::vector<std::string>& ignoreList) const { return ""; }
// Creates a copy of this element.
// This method **must** be implemented in a `final` class only.
virtual std::shared_ptr<ParamBase> clone() const = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/Ethereum/ABI/ParamStruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ std::shared_ptr<ParamBase> ParamStruct::clone() const {
return std::make_shared<ParamStruct>(_name, _params.clone());
}

std::shared_ptr<ParamBase> ParamStruct::clone() const {
return std::make_shared<ParamStruct>(_name, _params.clone());
}

Data ParamStruct::hashStructJson(const std::string& messageJson) {
auto message = json::parse(messageJson, nullptr, false);
if (message.is_discarded()) {
Expand Down
11 changes: 7 additions & 4 deletions src/Ethereum/ABI/ParamStruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ParamNamed final : public ParamBase
bool decode(const Data& encoded, size_t& offset_inout) override { return _param->decode(encoded, offset_inout); }
bool setValueJson(const std::string& value) override { return _param->setValueJson(value); }
Data hashStruct() const override { return _param->hashStruct(); }
void fillExtraTypesMap(ExtraTypesMap& extraTypes) const override { _param->fillExtraTypesMap(extraTypes); }
std::string getExtraTypes(std::vector<std::string>& ignoreList) const override { return _param->getExtraTypes(ignoreList); }
std::shared_ptr<ParamBase> clone() const override { return cloneNamed(); }
std::shared_ptr<ParamNamed> cloneNamed() const;
};
Expand All @@ -56,7 +56,7 @@ class ParamSetNamed {
std::shared_ptr<ParamNamed> getParam(int idx) const { return _params[idx]; }
std::string getType() const;
Data encodeHashes() const;
void fillExtraTypesMap(ExtraTypesMap& extraTypes) const;
std::string getExtraTypes(std::vector<std::string>& ignoreList) const;
std::shared_ptr<ParamNamed> findParamByName(const std::string& name) const;
ParamSetNamed clone() const;
};
Expand All @@ -79,7 +79,10 @@ class ParamStruct final : public ParamCollection
/// Compute the hash of a struct, used for signing, according to EIP712
Data hashStruct() const override;
/// Get full type, extended by used sub-types, of the form 'Mail(Person from,Person to,string contents)Person(string name,address wallet)'
std::string encodeType() const;
std::string encodeType() const {
std::vector<std::string> ignoreList;
return getExtraTypes(ignoreList);
}
/// Get the hash of the full type.
Data hashType() const;

Expand All @@ -90,7 +93,7 @@ class ParamStruct final : public ParamCollection
bool decode([[maybe_unused]] const Data& encoded, [[maybe_unused]] size_t& offset_inout) override { return true; }
bool setValueJson([[maybe_unused]] const std::string& value) override { return false; } // see makeStruct
Data encodeHashes() const;
void fillExtraTypesMap(ExtraTypesMap& extraTypes) const override;
std::string getExtraTypes(std::vector<std::string>& ignoreList) const override;
std::shared_ptr<ParamBase> clone() const override;
std::shared_ptr<ParamNamed> findParamByName(const std::string& name) const { return _params.findParamByName(name); }

Expand Down
7 changes: 3 additions & 4 deletions src/Ethereum/Barz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "EIP1014.h"
#include "Hash.h"
#include "HexCoding.h"
#include <WebAuthn.h>
#include "../proto/Barz.pb.h"
#include "AsnParser.h"
#include "Base64.h"
Expand All @@ -35,15 +34,15 @@ std::string getCounterfactualAddress(const Proto::ContractAddressInput input) {
append(initCode, encoded);

const Data initCodeHash = Hash::keccak256(initCode);
const Data salt(32, 0);
Data salt = store(input.salt(), 32);
return Ethereum::checksumed(Ethereum::Address(hexEncoded(Ethereum::create2Address(input.factory(), salt, initCodeHash))));
}

Data getInitCode(const std::string& factoryAddress, const PublicKey& publicKey, const std::string& verificationFacet) {
Data getInitCode(const std::string& factoryAddress, const PublicKey& publicKey, const std::string& verificationFacet, const uint32_t salt) {
auto createAccountFunc = Ethereum::ABI::Function("createAccount", ParamCollection{
std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(verificationFacet)),
std::make_shared<Ethereum::ABI::ParamByteArray>(publicKey.bytes),
std::make_shared<Ethereum::ABI::ParamUInt256>(0)});
std::make_shared<Ethereum::ABI::ParamUInt256>(salt)});
Data createAccountFuncEncoded;
createAccountFunc.encode(createAccountFuncEncoded);

Expand Down
2 changes: 1 addition & 1 deletion src/Ethereum/Barz.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace TW::Barz {

std::string getCounterfactualAddress(const Proto::ContractAddressInput input);
Data getInitCode(const std::string& factoryAddress, const PublicKey& publicKey, const std::string& verificationFacet);
Data getInitCode(const std::string& factoryAddress, const PublicKey& publicKey, const std::string& verificationFacet, const uint32_t salt);
Data getFormattedSignature(const Data& signature, const Data challenge, const Data& authenticatorData, const std::string& clientDataJSON);

}
4 changes: 2 additions & 2 deletions src/interface/TWBarz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ TWString *_Nonnull TWBarzGetCounterfactualAddress(TWData *_Nonnull input) {
return TWStringCreateWithUTF8Bytes(TW::Barz::getCounterfactualAddress(inputProto).c_str());
}

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) {
const auto& factoryStr = *reinterpret_cast<const std::string*>(factory);
const auto& publicKeyConverted = *reinterpret_cast<const TW::PublicKey*>(publicKey);
const auto& verificationFacetStr = *reinterpret_cast<const std::string*>(verificationFacet);

const auto initCode = TW::Barz::getInitCode(factoryStr, publicKeyConverted, verificationFacetStr);
const auto initCode = TW::Barz::getInitCode(factoryStr, publicKeyConverted, verificationFacetStr, salt);
return TWDataCreateWithData(&initCode);
}

Expand Down
3 changes: 3 additions & 0 deletions src/proto/Barz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ message ContractAddressInput {
string bytecode = 7;
// PublicKey of the wallet
string public_key = 8;

// Salt is used to derive multiple account from the same public key
uint32 salt = 9;
}
Loading

0 comments on commit a104f8d

Please sign in to comment.