Skip to content

Commit

Permalink
Merges the wallet protocol and behaviour into behaviour.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesduncombe committed Mar 21, 2024
1 parent 9d98caa commit 9c53b3a
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 107 deletions.
17 changes: 0 additions & 17 deletions lib/tt_eth/behaviours/wallet.ex

This file was deleted.

32 changes: 32 additions & 0 deletions lib/tt_eth/behaviours/wallet_adapter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule TTEth.Behaviours.WalletAdapter do
@moduledoc """
Defines a shared behaviour for wallet adapters.
"""

@typedoc """
This represents the config for a wallet adapter.
Check the documentation for the adapter for specific configuration options.
"""
@type config :: map() | binary()

@typedoc """
Represents a wallet adapter.
"""
@type wallet_adapter :: struct()

@doc """
Returns a new populated wallet adapter struct.
"""
@callback new(config) :: wallet_adapter

@doc """
Provides the attributes needed to build a `Wallet.t` using the passed `wallet_adapter`.
"""
@callback wallet_attrs(wallet_adapter) :: map()

@doc """
Signs `digest` using the given `wallet_adapter`.
"""
@callback sign(wallet_adapter, digest :: binary()) :: {:ok, binary()} | {:error, any()}
end
58 changes: 29 additions & 29 deletions lib/tt_eth/local_wallet.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,56 +14,56 @@ defmodule TTEth.LocalWallet do
"""
alias TTEth.Type.{Address, PublicKey, PrivateKey}
alias TTEth.Secp256k1
alias TTEth.Behaviours.Wallet, as: WalletBehaviour
alias TTEth.Behaviours.WalletAdapter, as: WalletAdapterBehaviour

@type t :: %__MODULE__{}

@behaviour WalletBehaviour
@behaviour WalletAdapterBehaviour

defstruct [
:private_key,
:human_private_key
]

defimpl TTEth.Protocols.Wallet, for: __MODULE__ do
def wallet_attrs(%@for{} = wallet) do
pub =
wallet.private_key
|> PublicKey.from_private_key!()
|> PublicKey.from_human!()

address = pub |> Address.from_public_key!()

[
address: address,
public_key: pub,
human_address: address |> Address.to_human!(),
human_public_key: pub |> PublicKey.to_human!(),
_adapter: wallet
]
end

def sign(%@for{} = wallet, "" <> digest),
do:
digest
|> Secp256k1.ecdsa_sign_compact(wallet.private_key)
end

@impl WalletBehaviour

def new(%{private_key: private_key} = _config),
@impl WalletAdapterBehaviour
def new(%{private_key: "" <> private_key} = _config),
do:
__MODULE__
|> struct!(%{
private_key: private_key |> PrivateKey.from_human!(),
human_private_key: private_key
})

@impl WalletAdapterBehaviour
def new("" <> private_key = _config),
do:
%{private_key: private_key}
|> new()

@impl WalletAdapterBehaviour
def wallet_attrs(%__MODULE__{} = wallet) do
pub =
wallet.private_key
|> PublicKey.from_private_key!()
|> PublicKey.from_human!()

address = pub |> Address.from_public_key!()

%{
address: address,
public_key: pub,
human_address: address |> Address.to_human!(),
human_public_key: pub |> PublicKey.to_human!(),
_adapter: wallet
}
end

@impl WalletAdapterBehaviour
def sign(%__MODULE__{} = wallet, "" <> digest),
do:
digest
|> Secp256k1.ecdsa_sign_compact(wallet.private_key)

## Helpers.

@doc """
Expand Down
21 changes: 0 additions & 21 deletions lib/tt_eth/protocols/wallet.ex

This file was deleted.

28 changes: 14 additions & 14 deletions lib/tt_eth/wallet.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ defmodule TTEth.Wallet do
@moduledoc """
Provides a handle struct - `TTEth.Wallet.t()` for encapsulating a wallet.
"""
alias TTEth.Protocols.Wallet, as: WalletProtocol
alias TTEth.Type.Signature, as: EthSignature
alias TTEth.Type.Address, as: EthAddress
alias TTEth.Type.PublicKey, as: EthPublicKey
Expand Down Expand Up @@ -59,21 +58,22 @@ defmodule TTEth.Wallet do
@doc """
Creates a new wallet from an underlying wallet or a random one.
"""
def new(wallet \\ TTEth.LocalWallet.generate()) when is_struct(wallet),
do:
__MODULE__
|> struct!(
wallet
|> WalletProtocol.wallet_attrs()
)
def new(%wallet_adapter{} = wallet \\ TTEth.LocalWallet.generate())
when is_struct(wallet),
do:
__MODULE__
|> struct!(
wallet
|> wallet_adapter.wallet_attrs()
)

@doc """
Signs a digest using the passed wallet.
"""
def sign(%__MODULE__{_adapter: wallet}, "" <> digest),
def sign(%__MODULE__{_adapter: %wallet_adapter{} = wallet_adapter_state}, "" <> digest),
do:
wallet
|> WalletProtocol.sign(digest)
wallet_adapter_state
|> wallet_adapter.sign(digest)

@doc """
Same as `sign/2` but raises if the signing process is not successful.
Expand Down Expand Up @@ -111,9 +111,9 @@ defmodule TTEth.Wallet do

## Private.

defp build_with_adapter!(config, adapter \\ TTEth.LocalWallet)
when (is_binary(config) or is_map(config)) and is_atom(adapter),
defp build_with_adapter!(config, wallet_adapter \\ TTEth.LocalWallet)
when (is_binary(config) or is_map(config)) and is_atom(wallet_adapter),
do:
config
|> adapter.new()
|> wallet_adapter.new()
end
5 changes: 1 addition & 4 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ defmodule TTEth.MixProject do
Behaviours: [
TTEth.Behaviours.ChainClient,
TTEth.Behaviours.Transaction,
TTEth.Behaviours.Wallet
],
Protocols: [
TTEth.Protocols.Wallet
TTEth.Behaviours.WalletAdapter
],
Types: [
TTEth.Type.Address,
Expand Down
41 changes: 19 additions & 22 deletions test/tt_eth/local_wallet_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,46 @@ defmodule TTEth.LocalWalletTest do
use TTEth.Case
alias TTEth.LocalWallet
alias TTEth.Type.PrivateKey
alias TTEth.Protocols.Wallet, as: WalletProtocol

@human_private_key "0xfa015243f2e6d8694ab037a7987dc73b1630fc8cb1ce82860344684c15d24026"

describe "implements TTEth.Protocols.Wallet protocol" do
setup :build_local_wallet
describe "implements TTEth.Behaviours.Wallet behaviour" do
setup [:build_local_wallet]

test "new/1 - initializes a new wallet adapter struct" do
decoded_private_key = @human_private_key |> PrivateKey.from_human!()

%{private_key: @human_private_key}
|> LocalWallet.new()
|> assert_match(%LocalWallet{
private_key: ^decoded_private_key,
human_private_key: @human_private_key
})
end

test "wallet_attrs/1 - returns attributes needed when building a wallet", %{
local_wallet: local_wallet
local_wallet: %wallet_adapter{} = local_wallet
} do
local_wallet
|> WalletProtocol.wallet_attrs()
|> assert_match(
|> wallet_adapter.wallet_attrs()
|> assert_match(%{
address: _,
public_key: _,
human_address: "0x" <> _,
human_public_key: "0x" <> _,
_adapter: ^local_wallet
)
})
end

test "sign/2 - signs the given digest with the wallet", %{
local_wallet: local_wallet
local_wallet: %wallet_adapter{} = local_wallet
} do
local_wallet
|> WalletProtocol.sign("some plaintext" |> TTEth.keccak())
|> wallet_adapter.sign("some plaintext" |> TTEth.keccak())
|> assert_match({:ok, {<<_signature::512>>, recovery_id}} when recovery_id in [0, 1])
end
end

describe "implements TTEth.Behaviours.Wallet behaviour" do
test "new/1 - initializes a new CloudKMS struct" do
decoded_private_key = @human_private_key |> PrivateKey.from_human!()

%{private_key: @human_private_key}
|> LocalWallet.new()
|> assert_match(%LocalWallet{
private_key: ^decoded_private_key,
human_private_key: @human_private_key
})
end
end

## Private.

defp build_local_wallet(_),
Expand Down

0 comments on commit 9c53b3a

Please sign in to comment.