Skip to content

Commit

Permalink
[ERC-4337] Making UserOp generation compatible with different wallet … (
Browse files Browse the repository at this point in the history
#3173)

* [ERC-4337] Making UserOp generation compatible with different wallet implementations

* Add init code

* Update BarzTests.swift

* update user op construction

* Fix swift tests

* remove old tests

* fix issues related to the new ethereum proto size

* update android tests

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* disable unity build and fix some warnings

* Fix android codegen Init check

* commit missing files

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* Update Barz.cpp

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

---------

Co-authored-by: hewigovens <[email protected]>
  • Loading branch information
rsrbk and hewigovens authored Jun 1, 2023
1 parent c0f2f84 commit 1240280
Show file tree
Hide file tree
Showing 31 changed files with 647 additions and 1,352 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,4 @@ class TestEthereumAddress {

assertFalse(AnyAddress.isValid("0xMQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4", CoinType.ETHEREUM))
}

@Test
fun testEthereumEIP4337DeploymentAddress() {
val factoryAddress = "0xd9145CCE52D386f254917e481eB44e9943F39138"
val logicAddress = "0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D"
val ownerAddress = "0xA5a1dddEF094095AfB7b6e322dE72961DF2e1988"
val result = Ethereum.eip4337GetDeploymentAddress(factoryAddress, logicAddress, ownerAddress)
assertEquals(result, "0xbEaA87cEEaC906C21aaacd258FbFB87CfA3c90a8")
}
}

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion codegen/lib/templates/jni/parameter_access.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%
method = locals[:method]
if method.static && !method.name.include?('Init')
if method.static && !method.name.start_with?('Init')
parameters = method.parameters
else
parameters = method.parameters.drop(1)
Expand Down
2 changes: 1 addition & 1 deletion codegen/lib/templates/jni/parameter_release.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%
method = locals[:method]
if method.static && !method.name.include?('Init')
if method.static && !method.name.start_with?('Init')
parameters = method.parameters
else
parameters = method.parameters.drop(1)
Expand Down
2 changes: 1 addition & 1 deletion codegen/lib/templates/kotlin_jni/parameter_access.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%
method = locals[:method]
if method.static && !method.name.include?('Init')
if method.static && !method.name.start_with?('Init')
parameters = method.parameters
else
parameters = method.parameters.drop(1)
Expand Down
2 changes: 1 addition & 1 deletion codegen/lib/templates/kotlin_jni/parameter_release.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%
method = locals[:method]
if method.static && !method.name.include?('Init')
if method.static && !method.name.start_with?('Init')
parameters = method.parameters
else
parameters = method.parameters.drop(1)
Expand Down
18 changes: 18 additions & 0 deletions include/TrustWalletCore/TWBarz.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,22 @@ struct TWBarz;
TW_EXPORT_STATIC_METHOD
TWString *_Nonnull TWBarzGetCounterfactualAddress(TWData *_Nonnull input);

/// Returns the init code parameter of ERC-4337 User Operation
///
/// \param factory Wallet factory address (BarzFactory)
/// \param publicKey Public key for the verification facet
/// \param verificationFacet Verification facet address
/// \return The address.
TW_EXPORT_STATIC_METHOD
TWData *_Nonnull TWBarzGetInitCodeFromPublicKey(TWString* _Nonnull factory, TWString* _Nonnull publicKey, TWString* _Nonnull verificationFacet);

/// Returns the init code parameter of ERC-4337 User Operation
///
/// \param factory Wallet factory address (BarzFactory)
/// \param attestationObject Attestation object from created webauthn credentials
/// \param verificationFacet Verification facet address
/// \return The address.
TW_EXPORT_STATIC_METHOD
TWData *_Nonnull TWBarzGetInitCodeFromAttestationObject(TWString* _Nonnull factory, TWString* _Nonnull attestationObject, TWString* _Nonnull verificationFacet);

TW_EXTERN_C_END
8 changes: 0 additions & 8 deletions include/TrustWalletCore/TWEthereum.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,4 @@ struct TWEthereum;
TW_EXPORT_STATIC_METHOD
TWString* _Nonnull TWEthereumEip2645GetPath(TWString* _Nonnull ethAddress, TWString* _Nonnull layer, TWString* _Nonnull application, TWString* _Nonnull index);

/// Generates a deployment address for a ERC-4337 compatible smart contract wallet
///
/// \param factoryAddress non-null address of the account factory
/// \param logicAddress non-null address of the wallet's logic smart contract
/// \param ownerAddress non-null address of the signing key that controls the smart contract wallet
/// \return Ethereum resulting address
TW_EXPORT_STATIC_METHOD
TWString* _Nonnull TWEthereumEip4337GetDeploymentAddress(TWString* _Nonnull factoryAddress, TWString* _Nonnull logicAddress, TWString* _Nonnull ownerAddress);
TW_EXTERN_C_END
4 changes: 2 additions & 2 deletions samples/kmp/shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ kotlin {
baseName = "shared"
}
}

sourceSets {
val commonMain by getting {
dependencies {
implementation("com.trustwallet:wallet-core-kotlin:3.1.31")
implementation("com.trustwallet:wallet-core-kotlin:3.1.36")
}
}
val commonTest by getting {
Expand Down
50 changes: 35 additions & 15 deletions src/Ethereum/Barz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,32 @@

namespace TW::Barz {

using ParamBasePtr = std::shared_ptr<TW::Ethereum::ABI::ParamBase>;
using ParamBasePtr = std::shared_ptr<Ethereum::ABI::ParamBase>;
using ParamCollection = std::vector<ParamBasePtr>;

std::string getCounterfactualAddress(const TW::Barz::Proto::ContractAddressInput input) {
auto params = TW::Ethereum::ABI::ParamTuple();
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_cut_facet())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.account_facet())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.verification_facet())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.entry_point())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.security_manager())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.facet_registry())));
std::string getCounterfactualAddress(const Proto::ContractAddressInput input) {
auto params = Ethereum::ABI::ParamTuple();
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_cut_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.account_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.verification_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.entry_point())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_loupe_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_init())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.facet_registry())));

Data publicKey;
switch (input.owner().kind_case()) {
case TW::Barz::Proto::ContractOwner::KindCase::KIND_NOT_SET:
case Proto::ContractOwner::KindCase::KIND_NOT_SET:
return "";
case TW::Barz::Proto::ContractOwner::KindCase::kPublicKey:
case Proto::ContractOwner::KindCase::kPublicKey:
publicKey = parse_hex(input.owner().public_key());
break;
case TW::Barz::Proto::ContractOwner::KindCase::kAttestationObject:
case Proto::ContractOwner::KindCase::kAttestationObject:
const auto attestationObject = parse_hex(input.owner().attestation_object());
publicKey = subData(TW::WebAuthn::getPublicKey(attestationObject)->bytes, 1); // Drop the first byte which corresponds to the public key type
publicKey = subData(WebAuthn::getPublicKey(attestationObject)->bytes, 1); // Drop the first byte which corresponds to the public key type
break;
}
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamByteArray>(publicKey));
params.addParam(std::make_shared<Ethereum::ABI::ParamByteArray>(publicKey));

Data encoded;
params.encode(encoded);
Expand All @@ -48,7 +49,26 @@ std::string getCounterfactualAddress(const TW::Barz::Proto::ContractAddressInput

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

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

Data envelope;
append(envelope, parse_hex(factoryAddress));
append(envelope, createAccountFuncEncoded);
return envelope;
}

Data getInitCodeFromAttestationObject(const std::string& factoryAddress, const std::string& attestationObject, const std::string& verificationFacet) {
const auto publicKey = subData(WebAuthn::getPublicKey(parse_hex(attestationObject))->bytes, 1);
return getInitCodeFromPublicKey(factoryAddress, hexEncoded(publicKey), verificationFacet);
}

} // namespace TW::Barz
5 changes: 3 additions & 2 deletions src/Ethereum/Barz.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace TW::Barz {

std::string getCounterfactualAddress(const TW::Barz::Proto::ContractAddressInput input);

std::string getCounterfactualAddress(const Proto::ContractAddressInput input);
Data getInitCodeFromPublicKey(const std::string& factoryAddress, const std::string& owner, const std::string& verificationFacet);
Data getInitCodeFromAttestationObject(const std::string& factoryAddress, const std::string& attestationObject, const std::string& verificationFacet);
}
63 changes: 0 additions & 63 deletions src/Ethereum/EIP4337.cpp

This file was deleted.

20 changes: 0 additions & 20 deletions src/Ethereum/EIP4337.h

This file was deleted.

32 changes: 32 additions & 0 deletions src/Ethereum/ERC4337.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright © 2017-2023 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 "ABI.h"
#include "AddressChecksum.h"
#include "EIP1014.h"
#include "EIP1967.h"
#include "Hash.h"
#include "HexCoding.h"
#include <iostream>

namespace TW::Ethereum {

using ParamBasePtr = std::shared_ptr<ABI::ParamBase>;
using ParamCollection = std::vector<ParamBasePtr>;

// https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/samples/SimpleAccount.sol#L57
Data getERC4337ExecuteBytecode(const Data& toAddress, const uint256_t& value, const Data& data) {
auto executeFunc = ABI::Function("execute", ParamCollection{
std::make_shared<ABI::ParamAddress>(toAddress),
std::make_shared<ABI::ParamUInt256>(value),
std::make_shared<ABI::ParamByteArray>(data)});
Data executeFuncEncoded;
executeFunc.encode(executeFuncEncoded);
return executeFuncEncoded;
}


} // namespace TW::Ethereum
16 changes: 16 additions & 0 deletions src/Ethereum/ERC4337.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright © 2017-2023 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 "uint256.h"

namespace TW::Ethereum {

Data getERC4337ExecuteBytecode(const Data& toAddress, const uint256_t& value, const Data& data);

}
Loading

0 comments on commit 1240280

Please sign in to comment.