Skip to content

Commit

Permalink
ETH-implicit account support (#10224)
Browse files Browse the repository at this point in the history
## Context
Tracking issue: #10018.
Design: near/NEPs#518 (comment).

### Goal
We want the NEAR Protocol's ecosystem to be closer with Ethereum by
integrating Web3 wallet support.
To accomplish that, some changes on the protocol level are needed with
an emphasis on user experience continuity.
Following the design, the main change on the protocol level would be to
have ETH-style addresses managed by a new `Wallet Contract` integrated
into the protocol.
For seamless onboarding of EVM users, the contract will be free of
charge.

### Previous work
This PR is built on top of a [preparatory
PR](#10020).
It reintroduces some changes from a [closed
PR](#10056) that follows an old
design.

## Summary
On a transfer to an ETH-implicit address:
1. An account is created at this address.
2. The account does not have any access key added. Thus, it is not
possible to make a transaction from this account directly.
3. The Wallet Contract (as a part of the protocol) is deployed to the
account. For this PR, an empty smart contract is used as a placeholder.

### Changes
- On a transfer to an ETH-implicit address, if an account does not exist
yet at this address:
   - Create account at this address.
- Deploy a `Wallet Contract` placeholder (empty contract now) to this
account.
- Update fee for a transfer to an ETH-implicit address to include
account creation cost. `Wallet Contract` deployment is free of charge
(user only pays for an increased storage).
- Tests:
- Test whether it is possible to create an ETH-implicit account by
making a transfer to that address, and whether further funds can be sent
to this account.
- Test that no access key is added to an ETH-implicit account (the
account is locked) and in consequence no transactions are possible from
this account.
- Guard the changes with `EthImplicitAccounts` protocol feature and
`eth_implicit_accounts` runtime config flag.

## Next work
- Discuss how the `Wallet Contract` should be integrated into the
protocol for efficiency.
- Use the `Wallet Contract` placeholder implementation that allows to
transfer funds only.
  • Loading branch information
staffik authored Nov 24, 2023
1 parent b9423cf commit 1a5c286
Show file tree
Hide file tree
Showing 70 changed files with 925 additions and 136 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions core/crypto/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ impl PublicKey {
Self::SECP256K1(_) => panic!(),
}
}

pub fn unwrap_as_secp256k1(&self) -> &Secp256K1PublicKey {
match self {
Self::SECP256K1(key) => key,
Self::ED25519(_) => panic!(),
}
}
}

// This `Hash` implementation is safe since it retains the property
Expand Down
7 changes: 5 additions & 2 deletions core/crypto/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ impl PublicKey {
let keypair = ed25519_key_pair_from_seed(seed);
PublicKey::ED25519(ED25519PublicKey(keypair.verifying_key().to_bytes()))
}
_ => unimplemented!(),
KeyType::SECP256K1 => {
let secret_key = SecretKey::SECP256K1(secp256k1_secret_key_from_seed(seed));
PublicKey::SECP256K1(secret_key.public_key().unwrap_as_secp256k1().clone())
}
}
}
}
Expand All @@ -40,7 +43,7 @@ impl SecretKey {
let keypair = ed25519_key_pair_from_seed(seed);
SecretKey::ED25519(ED25519SecretKey(keypair.to_keypair_bytes()))
}
_ => SecretKey::SECP256K1(secp256k1_secret_key_from_seed(seed)),
KeyType::SECP256K1 => SecretKey::SECP256K1(secp256k1_secret_key_from_seed(seed)),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/primitives-core/src/parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ pub enum Parameter {
AltBn128,
FunctionCallWeight,
VmKind,
EthImplicitAccounts,
}

#[derive(
Expand Down
38 changes: 25 additions & 13 deletions core/primitives-core/src/runtime/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,30 @@ impl StorageUsageConfig {
}

/// Helper functions for computing Transfer fees.
/// In case of implicit account creation they always include extra fees for the CreateAccount and
/// In case of implicit account creation they include extra fees for the CreateAccount and
/// AddFullAccessKey (for NEAR-implicit account only) actions that are implicit.
/// We can assume that no overflow will happen here.
pub fn transfer_exec_fee(
cfg: &RuntimeFeesConfig,
implicit_account_creation_allowed: bool,
eth_implicit_accounts_enabled: bool,
receiver_account_type: AccountType,
) -> Gas {
let transfer_fee = cfg.fee(ActionCosts::transfer).exec_fee();
match (implicit_account_creation_allowed, receiver_account_type) {
match (implicit_account_creation_allowed, eth_implicit_accounts_enabled, receiver_account_type)
{
// Regular transfer to a named account.
(_, AccountType::NamedAccount) => transfer_fee,
(_, _, AccountType::NamedAccount) => transfer_fee,
// No account will be created, just a regular transfer.
(false, _) => transfer_fee,
// Currently, no account is created on transfer to ETH-implicit account, just a regular transfer.
(true, AccountType::EthImplicitAccount) => transfer_fee,
(false, _, _) => transfer_fee,
// No account will be created, just a regular transfer.
(true, false, AccountType::EthImplicitAccount) => transfer_fee,
// Extra fee for the CreateAccount.
(true, true, AccountType::EthImplicitAccount) => {
transfer_fee + cfg.fee(ActionCosts::create_account).exec_fee()
}
// Extra fees for the CreateAccount and AddFullAccessKey.
(true, AccountType::NearImplicitAccount) => {
(true, _, AccountType::NearImplicitAccount) => {
transfer_fee
+ cfg.fee(ActionCosts::create_account).exec_fee()
+ cfg.fee(ActionCosts::add_full_access_key).exec_fee()
Expand All @@ -232,18 +238,24 @@ pub fn transfer_send_fee(
cfg: &RuntimeFeesConfig,
sender_is_receiver: bool,
implicit_account_creation_allowed: bool,
eth_implicit_accounts_enabled: bool,
receiver_account_type: AccountType,
) -> Gas {
let transfer_fee = cfg.fee(ActionCosts::transfer).send_fee(sender_is_receiver);
match (implicit_account_creation_allowed, receiver_account_type) {
match (implicit_account_creation_allowed, eth_implicit_accounts_enabled, receiver_account_type)
{
// Regular transfer to a named account.
(_, AccountType::NamedAccount) => transfer_fee,
(_, _, AccountType::NamedAccount) => transfer_fee,
// No account will be created, just a regular transfer.
(false, _) => transfer_fee,
// Currently, no account is created on transfer to ETH-implicit account, just a regular transfer.
(true, AccountType::EthImplicitAccount) => transfer_fee,
(false, _, _) => transfer_fee,
// No account will be created, just a regular transfer.
(true, false, AccountType::EthImplicitAccount) => transfer_fee,
// Extra fee for the CreateAccount.
(true, true, AccountType::EthImplicitAccount) => {
transfer_fee + cfg.fee(ActionCosts::create_account).send_fee(sender_is_receiver)
}
// Extra fees for the CreateAccount and AddFullAccessKey.
(true, AccountType::NearImplicitAccount) => {
(true, _, AccountType::NearImplicitAccount) => {
transfer_fee
+ cfg.fee(ActionCosts::create_account).send_fee(sender_is_receiver)
+ cfg.fee(ActionCosts::add_full_access_key).send_fee(sender_is_receiver)
Expand Down
2 changes: 2 additions & 0 deletions core/primitives-core/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub enum ProtocolFeature {
/// NEP: https://github.com/near/NEPs/pull/509
#[cfg(feature = "protocol_feature_chunk_validation")]
ChunkValidation,
EthImplicitAccounts,
}

impl ProtocolFeature {
Expand Down Expand Up @@ -183,6 +184,7 @@ impl ProtocolFeature {
ProtocolFeature::SimpleNightshadeV2 => 135,
#[cfg(feature = "protocol_feature_chunk_validation")]
ProtocolFeature::ChunkValidation => 137,
ProtocolFeature::EthImplicitAccounts => 138,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions core/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ serde.workspace = true
serde_json.workspace = true
serde_with.workspace = true
serde_yaml.workspace = true
sha3.workspace = true
smart-default.workspace = true
stdx.workspace = true
strum.workspace = true
thiserror.workspace = true
time.workspace = true
tracing.workspace = true
wat.workspace = true

near-crypto.workspace = true
near-fmt.workspace = true
Expand Down
1 change: 1 addition & 0 deletions core/primitives/res/runtime_configs/138.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
eth_implicit_accounts: { old: false, new: true }
1 change: 1 addition & 0 deletions core/primitives/res/runtime_configs/parameters.snap
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,5 @@ ed25519_verify true
alt_bn128 true
function_call_weight true
vm_kind NearVm
eth_implicit_accounts false

1 change: 1 addition & 0 deletions core/primitives/res/runtime_configs/parameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,4 @@ ed25519_verify: false
alt_bn128: false
function_call_weight: false
vm_kind: Wasmer0
eth_implicit_accounts: false
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,4 @@ ed25519_verify: false
alt_bn128: false
function_call_weight: false
vm_kind: Wasmer0
eth_implicit_accounts: false
6 changes: 3 additions & 3 deletions core/primitives/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,9 +486,9 @@ pub enum ActionErrorKind {
/// Error occurs when a new `ActionReceipt` created by the `FunctionCall` action fails
/// receipt validation.
NewReceiptValidationError(ReceiptValidationError),
/// Error occurs when a `CreateAccount` action is called on hex-characters
/// account of length 64. See implicit account creation NEP:
/// <https://github.com/nearprotocol/NEPs/pull/71>.
/// Error occurs when a `CreateAccount` action is called on a NEAR-implicit or ETH-implicit account.
/// See NEAR-implicit account creation NEP: <https://github.com/nearprotocol/NEPs/pull/71>.
/// Also, see ETH-implicit account creation NEP: <https://github.com/near/NEPs/issues/518>.
///
/// TODO(#8598): This error is named very poorly. A better name would be
/// `OnlyNamedAccountCreationAllowed`.
Expand Down
2 changes: 2 additions & 0 deletions core/primitives/src/runtime/config_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ static CONFIG_DIFFS: &[(ProtocolVersion, &str)] = &[
(63, include_config!("63.yaml")),
(64, include_config!("64.yaml")),
(129, include_config!("129.yaml")),
// Introduce ETH-implicit accounts.
(138, include_config!("138.yaml")),
];

/// Testnet parameters for versions <= 29, which (incorrectly) differed from mainnet parameters
Expand Down
1 change: 1 addition & 0 deletions core/primitives/src/runtime/parameter_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ impl TryFrom<&ParameterTable> for RuntimeConfig {
ed25519_verify: params.get(Parameter::Ed25519Verify)?,
alt_bn128: params.get(Parameter::AltBn128)?,
function_call_weight: params.get(Parameter::FunctionCallWeight)?,
eth_implicit_accounts: params.get(Parameter::EthImplicitAccounts)?,
},
account_creation_config: AccountCreationConfig {
min_allowed_top_level_account_length: params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ expression: config_view
"ed25519_verify": false,
"alt_bn128": false,
"function_call_weight": false,
"eth_implicit_accounts": false,
"limit_config": {
"max_gas_burnt": 200000000000000,
"max_stack_height": 16384,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ expression: config_view
"ed25519_verify": true,
"alt_bn128": true,
"function_call_weight": true,
"eth_implicit_accounts": false,
"limit_config": {
"max_gas_burnt": 300000000000000,
"max_stack_height": 262144,
Expand Down
Loading

0 comments on commit 1a5c286

Please sign in to comment.