Skip to content

Commit bb2ff95

Browse files
authored
feat: save and display aexn extensions (#710)
1 parent d718c0a commit bb2ff95

21 files changed

+264
-99
lines changed

lib/ae_mdw/aex9.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule AeMdw.Aex9 do
44
"""
55

66
alias AeMdw.Collection
7-
alias AeMdw.Contracts.AexnContract
7+
alias AeMdw.AexnContracts
88
alias AeMdw.Database
99
alias AeMdw.Db.Format
1010
alias AeMdw.Db.Model
@@ -113,7 +113,7 @@ defmodule AeMdw.Aex9 do
113113
{:ok, balances_cursor() | nil, [aex9_balance()], balances_cursor() | nil}
114114
| {:error, Error.t()}
115115
def fetch_balances(contract_pk, pagination, cursor) do
116-
if AexnContract.is_aex9?(contract_pk) do
116+
if AexnContracts.is_aex9?(contract_pk) do
117117
{amounts, _height_hash} = Db.aex9_balances!(contract_pk)
118118
accounts_pks = amounts |> Map.keys() |> Enum.sort()
119119
cursor = deserialize_balances_cursor(cursor)
@@ -390,7 +390,7 @@ defmodule AeMdw.Aex9 do
390390
end
391391

392392
defp validate_aex9(contract_pk) do
393-
if AexnContract.is_aex9?(contract_pk) do
393+
if AexnContracts.is_aex9?(contract_pk) do
394394
:ok
395395
else
396396
{:error,

lib/ae_mdw/contracts/aexn_contract.ex renamed to lib/ae_mdw/aexn_contracts.ex

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule AeMdw.Contracts.AexnContract do
1+
defmodule AeMdw.AexnContracts do
22
@moduledoc """
33
AEX-N detection and common calls to interact with the contract.
44
"""
@@ -30,7 +30,7 @@ defmodule AeMdw.Contracts.AexnContract do
3030
@spec is_aex141?(pubkey()) :: boolean()
3131
def is_aex141?(pubkey) when is_binary(pubkey) do
3232
with {:ok, {type_info, _compiler_vsn, _source_hash}} <- Contract.get_info(pubkey),
33-
true <- has_all_aex141_signatures?(type_info),
33+
true <- valid_aex141_signatures?(type_info),
3434
{:ok, extensions} <- call_contract(pubkey, "aex141_extensions") do
3535
has_valid_aex141_extensions?(extensions, type_info)
3636
else
@@ -39,15 +39,50 @@ defmodule AeMdw.Contracts.AexnContract do
3939
end
4040
end
4141

42-
def is_aex141?(_no_fcode), do: false
42+
@spec has_aex141_signatures?(pubkey()) :: boolean()
43+
def has_aex141_signatures?(pubkey) do
44+
case Contract.get_info(pubkey) do
45+
{:ok, {type_info, _compiler_vsn, _source_hash}} ->
46+
valid_aex141_signatures?(type_info)
47+
48+
{:error, _reason} ->
49+
false
50+
end
51+
end
52+
53+
@spec has_valid_aex141_extensions?(Model.aexn_extensions(), pubkey() | Contract.type_info()) ::
54+
boolean()
55+
def has_valid_aex141_extensions?(extensions, pubkey) when is_binary(pubkey) do
56+
case Contract.get_info(pubkey) do
57+
{:ok, {type_info, _compiler_vsn, _source_hash}} ->
58+
has_valid_aex141_extensions?(extensions, type_info)
59+
60+
{:error, _reason} ->
61+
false
62+
end
63+
end
4364

44-
@spec call_meta_info(pubkey()) :: {:ok, Model.aexn_meta_info()} | :not_found
65+
def has_valid_aex141_extensions?(extensions, {:fcode, functions, _hash_names, _code}) do
66+
Enum.all?(extensions, &valid_aex141_extension?(&1, functions))
67+
end
68+
69+
def has_valid_aex141_extensions?(_extensions, _no_fcode), do: false
70+
71+
@spec call_meta_info(pubkey()) :: {:ok, Model.aexn_meta_info()} | :error
4572
def call_meta_info(contract_pk) do
4673
with {:ok, {:tuple, meta_info_tuple}} <- call_contract(contract_pk, "meta_info", []) do
4774
{:ok, decode_meta_info(meta_info_tuple)}
4875
end
4976
end
5077

78+
@spec call_extensions(Model.aexn_type(), pubkey()) :: {:ok, Model.aexn_extensions()} | :error
79+
def call_extensions(aexn_type, pubkey) do
80+
case aexn_type do
81+
:aex9 -> call_contract(pubkey, "aex9_extensions")
82+
:aex141 -> call_contract(pubkey, "aex141_extensions")
83+
end
84+
end
85+
5186
#
5287
# Private functions
5388
#
@@ -58,9 +93,9 @@ defmodule AeMdw.Contracts.AexnContract do
5893
{:ok, return} ->
5994
{:ok, return}
6095

61-
{:error, _call_error} ->
62-
Log.warn("#{method} call error for #{enc_ct(contract_pk)}")
63-
:not_found
96+
{:error, call_error} ->
97+
Log.warn("#{method} call error for #{enc_ct(contract_pk)}: #{inspect(call_error)}")
98+
:error
6499
end
65100
end
66101

@@ -69,6 +104,7 @@ defmodule AeMdw.Contracts.AexnContract do
69104
defp decode_meta_info({name, symbol, variant_url, variant_type}) do
70105
url =
71106
case variant_url do
107+
{:variant, [0, 1], 1, {url}} -> url
72108
{:variant, [0, 1], 1, url} -> url
73109
_other -> nil
74110
end
@@ -90,15 +126,15 @@ defmodule AeMdw.Contracts.AexnContract do
90126
end)
91127
end
92128

93-
defp has_all_aex141_signatures?({:fcode, functions, _hash_names, _code}) do
129+
defp valid_aex141_signatures?({:fcode, functions, _hash_names, _code}) do
94130
valid_base_signatures? =
95131
AeMdw.Node.aex141_signatures()
96132
|> has_all_signatures?(functions)
97133

98134
valid_base_signatures? and valid_aex141_metadata?(functions)
99135
end
100136

101-
defp has_all_aex141_signatures?(_no_fcode), do: false
137+
defp valid_aex141_signatures?(_no_fcode), do: false
102138

103139
@option_string {:variant, [tuple: [], tuple: [:string]]}
104140
@option_metadata_map {:variant, [tuple: [], tuple: [{:map, :string, :string}]]}
@@ -119,10 +155,6 @@ defmodule AeMdw.Contracts.AexnContract do
119155
end
120156
end
121157

122-
defp has_valid_aex141_extensions?(extensions, {:fcode, functions, _hash_names, _code}) do
123-
Enum.all?(extensions, &valid_aex141_extension?(&1, functions))
124-
end
125-
126158
defp valid_aex141_extension?("mintable", functions) do
127159
case Map.get(functions, @mint_hash) do
128160
nil ->
@@ -143,4 +175,6 @@ defmodule AeMdw.Contracts.AexnContract do
143175
match?({_code, {[:address], :integer}, _body}, functions[@check_swap_hash]) and
144176
match?({_code, {[], {:map, :address, :string}}, _body}, functions[@swapped_hash])
145177
end
178+
179+
defp valid_aex141_extension?(_any, _functions), do: false
146180
end

lib/ae_mdw/db/contract.ex

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule AeMdw.Db.Contract do
44
"""
55
alias AeMdw.Collection
66
alias AeMdw.Contract
7-
alias AeMdw.Contracts.AexnContract
7+
alias AeMdw.AexnContracts
88
alias AeMdw.Database
99
alias AeMdw.Db.Model
1010
alias AeMdw.Db.Origin
@@ -35,9 +35,10 @@ defmodule AeMdw.Db.Contract do
3535
Model.aexn_type(),
3636
Model.aexn_meta_info(),
3737
pubkey(),
38-
integer()
38+
integer(),
39+
Model.aexn_extensions()
3940
) :: state()
40-
def aexn_creation_write(state, aexn_type, aexn_meta_info, contract_pk, txi) do
41+
def aexn_creation_write(state, aexn_type, aexn_meta_info, contract_pk, txi, extensions) do
4142
name = elem(aexn_meta_info, 0)
4243
symbol = elem(aexn_meta_info, 1)
4344

@@ -48,7 +49,8 @@ defmodule AeMdw.Db.Contract do
4849
Model.aexn_contract(
4950
index: {aexn_type, contract_pk},
5051
txi: txi,
51-
meta_info: aexn_meta_info
52+
meta_info: aexn_meta_info,
53+
extensions: extensions
5254
)
5355

5456
state
@@ -246,11 +248,11 @@ defmodule AeMdw.Db.Contract do
246248

247249
@spec which_aexn_contract_pubkey(pubkey(), pubkey()) :: pubkey() | nil
248250
def which_aexn_contract_pubkey(contract_pk, addr) do
249-
if AexnContract.is_aex9?(contract_pk) do
251+
if AexnContracts.is_aex9?(contract_pk) do
250252
contract_pk
251253
else
252254
# remotely called contract is aex9?
253-
if addr != contract_pk and AexnContract.is_aex9?(addr), do: addr
255+
if addr != contract_pk and AexnContracts.is_aex9?(addr), do: addr
254256
end
255257
end
256258

@@ -356,17 +358,18 @@ defmodule AeMdw.Db.Contract do
356358

357359
@spec update_aex9_state(State.t(), pubkey(), block_index(), txi()) :: State.t()
358360
def update_aex9_state(state, contract_pk, {kbi, mbi} = block_index, txi) do
359-
if AexnContract.is_aex9?(contract_pk) do
361+
if AexnContracts.is_aex9?(contract_pk) do
360362
with false <- State.exists?(state, Model.AexnContract, {:aex9, contract_pk}),
361-
{:ok, aex9_meta_info} <- AexnContract.call_meta_info(contract_pk) do
363+
{:ok, extensions} <- AexnContracts.call_extensions(:aex9, contract_pk),
364+
{:ok, aex9_meta_info} <- AexnContracts.call_meta_info(contract_pk) do
362365
AsyncTasks.Producer.enqueue(:derive_aex9_presence, [contract_pk, kbi, mbi, txi])
363-
aexn_creation_write(state, :aex9, aex9_meta_info, contract_pk, txi)
366+
aexn_creation_write(state, :aex9, aex9_meta_info, contract_pk, txi, extensions)
364367
else
365368
true ->
366369
AsyncTasks.Producer.enqueue(:update_aex9_state, [contract_pk], [block_index, txi])
367370
state
368371

369-
:not_found ->
372+
:error ->
370373
state
371374
end
372375
else

lib/ae_mdw/db/model.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,20 @@ defmodule AeMdw.Db.Model do
308308
@type aex9_meta_info :: {aexn_name(), aexn_symbol(), non_neg_integer()}
309309
@type aex141_meta_info :: {aexn_name(), aexn_symbol(), String.t(), atom()}
310310
@type aexn_meta_info :: aex9_meta_info() | aex141_meta_info()
311+
@type aexn_extensions :: [String.t()]
311312

312313
@type aexn_contract ::
313314
record(:aexn_contract,
314315
index: {aexn_type(), Db.pubkey()},
315316
txi: Txs.txi(),
316-
meta_info: aexn_meta_info()
317+
meta_info: aexn_meta_info(),
318+
extensions: aexn_extensions()
317319
)
318320
@aexn_contract_defaults [
319321
index: nil,
320322
txi: -1,
321-
meta_info: nil
323+
meta_info: nil,
324+
extensions: []
322325
]
323326
defrecord :aexn_contract, @aexn_contract_defaults
324327

lib/ae_mdw/db/mutations/aexn_create_contract_mutation.ex

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ defmodule AeMdw.Db.AexnCreateContractMutation do
55

66
alias AeMdw.Blocks
77
alias AeMdw.Db.Contract, as: DBContract
8+
alias AeMdw.Db.Model
89
alias AeMdw.Db.State
910
alias AeMdw.Sync.AsyncTasks
1011
alias AeMdw.Txs
@@ -15,7 +16,8 @@ defmodule AeMdw.Db.AexnCreateContractMutation do
1516
:contract_pk,
1617
:aexn_meta_info,
1718
:block_index,
18-
:create_txi
19+
:create_txi,
20+
:extensions
1921
]
2022

2123
@typep aexn_type :: AeMdw.Db.Model.aexn_type()
@@ -27,23 +29,26 @@ defmodule AeMdw.Db.AexnCreateContractMutation do
2729
contract_pk: pubkey(),
2830
aexn_meta_info: aexn_meta_info(),
2931
block_index: Blocks.block_index(),
30-
create_txi: Txs.txi()
32+
create_txi: Txs.txi(),
33+
extensions: Model.aexn_extensions()
3134
}
3235

3336
@spec new(
3437
aexn_type(),
3538
pubkey(),
3639
aexn_meta_info(),
3740
Blocks.block_index(),
38-
Txs.txi()
41+
Txs.txi(),
42+
Model.aexn_extensions()
3943
) :: t()
40-
def new(aexn_type, contract_pk, aexn_meta_info, block_index, create_txi) do
44+
def new(aexn_type, contract_pk, aexn_meta_info, block_index, create_txi, extensions) do
4145
%__MODULE__{
4246
aexn_type: aexn_type,
4347
contract_pk: contract_pk,
4448
aexn_meta_info: aexn_meta_info,
4549
block_index: block_index,
46-
create_txi: create_txi
50+
create_txi: create_txi,
51+
extensions: extensions
4752
}
4853
end
4954

@@ -54,12 +59,20 @@ defmodule AeMdw.Db.AexnCreateContractMutation do
5459
contract_pk: contract_pk,
5560
aexn_meta_info: aexn_meta_info,
5661
block_index: {kbi, mbi},
57-
create_txi: create_txi
62+
create_txi: create_txi,
63+
extensions: extensions
5864
},
5965
state
6066
) do
6167
state =
62-
DBContract.aexn_creation_write(state, aexn_type, aexn_meta_info, contract_pk, create_txi)
68+
DBContract.aexn_creation_write(
69+
state,
70+
aexn_type,
71+
aexn_meta_info,
72+
contract_pk,
73+
create_txi,
74+
extensions
75+
)
6376

6477
if aexn_type == :aex9 do
6578
AsyncTasks.Producer.enqueue(:derive_aex9_presence, [contract_pk, kbi, mbi, create_txi])

lib/ae_mdw/db/mutations/contract_call_mutation.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule AeMdw.Db.ContractCallMutation do
55

66
alias AeMdw.Blocks
77
alias AeMdw.Contract
8-
alias AeMdw.Contracts.AexnContract
8+
alias AeMdw.AexnContracts
99
alias AeMdw.Db.Contract, as: DBContract
1010
alias AeMdw.Db.Origin
1111
alias AeMdw.Db.State
@@ -60,7 +60,7 @@ defmodule AeMdw.Db.ContractCallMutation do
6060
state
6161
) do
6262
# update balance on any aex9 call
63-
if AexnContract.is_aex9?(contract_pk) do
63+
if AexnContracts.is_aex9?(contract_pk) do
6464
AsyncTasks.Producer.enqueue(:update_aex9_state, [contract_pk], [block_index, txi])
6565
end
6666

lib/ae_mdw/db/sync/contract.ex

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule AeMdw.Db.Sync.Contract do
44
"""
55
alias AeMdw.Blocks
66
alias AeMdw.Contract
7-
alias AeMdw.Contracts.AexnContract
7+
alias AeMdw.AexnContracts
88
alias AeMdw.Db.IntCallsMutation
99
alias AeMdw.Db.Model
1010
alias AeMdw.Db.Mutation
@@ -112,21 +112,26 @@ defmodule AeMdw.Db.Sync.Contract do
112112
def aexn_create_contract_mutation(contract_pk, block_index, txi) do
113113
aexn_type =
114114
cond do
115-
AexnContract.is_aex9?(contract_pk) -> :aex9
116-
AexnContract.is_aex141?(contract_pk) -> :aex141
115+
AexnContracts.is_aex9?(contract_pk) -> :aex9
116+
AexnContracts.has_aex141_signatures?(contract_pk) -> :aex141
117117
true -> nil
118118
end
119119

120120
with true <- aexn_type != nil,
121-
{:ok, aexn_meta_info} <-
122-
AexnContract.call_meta_info(contract_pk) do
123-
AexnCreateContractMutation.new(
124-
aexn_type,
125-
contract_pk,
126-
aexn_meta_info,
127-
block_index,
128-
txi
129-
)
121+
{:ok, aexn_extensions} <- AexnContracts.call_extensions(aexn_type, contract_pk),
122+
{:ok, aexn_meta_info} <- AexnContracts.call_meta_info(contract_pk) do
123+
if aexn_type == :aex9 or
124+
(aexn_type == :aex141 and
125+
AexnContracts.has_valid_aex141_extensions?(aexn_extensions, contract_pk)) do
126+
AexnCreateContractMutation.new(
127+
aexn_type,
128+
contract_pk,
129+
aexn_meta_info,
130+
block_index,
131+
txi,
132+
aexn_extensions
133+
)
134+
end
130135
else
131136
_false_or_notfound ->
132137
nil

0 commit comments

Comments
 (0)