Skip to content

Commit 03ae588

Browse files
authored
chore: return nil for invalid amount of aex9 holders (#1409)
1 parent 3245573 commit 03ae588

File tree

4 files changed

+119
-2
lines changed

4 files changed

+119
-2
lines changed

docs/swagger_v2/aexn.spec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ schemas:
162162
items:
163163
type: string
164164
holders:
165-
description: Count of accounts having balance
165+
description: Count of accounts having balance (nil when contract is not complaint)
166166
type: integer
167167
name:
168168
description: The name of AEX9 token

lib/ae_mdw_web/views/aexn_view.ex

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ defmodule AeMdwWeb.AexnView do
133133
:not_found -> 0
134134
end
135135

136+
num_holders =
137+
with num when num < 0 <- Stats.fetch_aex9_holders_count(state, contract_pk) do
138+
nil
139+
end
140+
136141
%{
137142
name: name,
138143
symbol: symbol,
@@ -142,7 +147,7 @@ defmodule AeMdwWeb.AexnView do
142147
extensions: extensions,
143148
initial_supply: initial_supply,
144149
event_supply: event_supply,
145-
holders: Stats.fetch_aex9_holders_count(state, contract_pk)
150+
holders: num_holders
146151
}
147152
end
148153

test/ae_mdw/db/contract_call_mutation_test.exs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,70 @@ defmodule AeMdw.Db.ContractCallMutationTest do
15111511
end
15121512
end
15131513

1514+
describe "aex9 non-compliant" do
1515+
test "call without a transfer event leads to negative aex9 holder count", %{store: store} do
1516+
unknown_event_hash = :crypto.strong_rand_bytes(32)
1517+
contract_pk = :crypto.strong_rand_bytes(32)
1518+
account_pk = :crypto.strong_rand_bytes(32)
1519+
amount = Enum.random(100_000_000..999_999_999)
1520+
height = Enum.random(100_000..999_999)
1521+
call_txi = Enum.random(100_000_000..999_999_999)
1522+
1523+
fun_arg_res = %{
1524+
arguments: [
1525+
%{
1526+
type: :address,
1527+
value: encode_account(account_pk)
1528+
},
1529+
%{
1530+
type: :int,
1531+
value: amount
1532+
}
1533+
],
1534+
function: "deposit",
1535+
result: %{type: :unit, value: ""}
1536+
}
1537+
1538+
call_rec =
1539+
call_rec("logs", contract_pk, height, nil, [
1540+
{
1541+
contract_pk,
1542+
[unknown_event_hash, account_pk, <<amount::256>>],
1543+
""
1544+
}
1545+
])
1546+
1547+
mutation =
1548+
ContractCallMutation.new(
1549+
contract_pk,
1550+
call_txi,
1551+
fun_arg_res,
1552+
call_rec
1553+
)
1554+
1555+
functions =
1556+
AeMdw.Node.aex9_signatures()
1557+
|> Enum.into(%{}, fn {hash, type} -> {hash, {nil, type, nil}} end)
1558+
1559+
type_info = {:fcode, functions, nil, nil}
1560+
AeMdw.EtsCache.put(AeMdw.Contract, contract_pk, {type_info, nil, nil})
1561+
1562+
store =
1563+
store
1564+
|> Store.put(
1565+
Model.Stat,
1566+
Model.stat(index: Stats.aex9_holder_count_key(contract_pk), payload: -1)
1567+
)
1568+
|> Store.put(
1569+
Model.Field,
1570+
Model.field(index: {:contract_create_tx, nil, contract_pk, call_txi - 1})
1571+
)
1572+
|> change_store([mutation])
1573+
1574+
assert -1 = Stats.fetch_aex9_holders_count(State.new(store), contract_pk)
1575+
end
1576+
end
1577+
15141578
defp contract_call_mutation(fname, call_txi, contract_pk) do
15151579
%{arguments: args} = fun_arg_res = fun_args_res(fname)
15161580
call_rec = call_rec(fname)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
defmodule AeMdwWeb.AexnViewTest do
2+
use ExUnit.Case
3+
4+
alias AeMdw.Db.Model
5+
alias AeMdw.Db.MemStore
6+
alias AeMdw.Db.NullStore
7+
alias AeMdw.Db.State
8+
alias AeMdw.Db.Sync.Stats
9+
alias AeMdwWeb.AexnView
10+
11+
import AeMdw.Util.Encoding
12+
13+
require Model
14+
15+
describe "render_contract/3" do
16+
test "returns NA for invalid amount of holders" do
17+
contract_pk = :crypto.strong_rand_bytes(32)
18+
contract_id = encode_contract(contract_pk)
19+
aex9_meta_info = {name, symbol, decimals} = {"Token1", "TK1", 18}
20+
txi = 1_123_456_789
21+
extensions = ["ext1", "ext2"]
22+
23+
state =
24+
NullStore.new()
25+
|> MemStore.new()
26+
|> State.new()
27+
|> Stats.decrement_aex9_holders(contract_pk)
28+
29+
m_aex9 =
30+
Model.aexn_contract(
31+
index: {:aex9, contract_pk},
32+
txi: txi,
33+
meta_info: aex9_meta_info,
34+
extensions: extensions
35+
)
36+
37+
assert %{
38+
name: ^name,
39+
symbol: ^symbol,
40+
decimals: ^decimals,
41+
contract_txi: ^txi,
42+
contract_id: ^contract_id,
43+
extensions: ^extensions,
44+
holders: nil
45+
} = AexnView.render_contract(state, m_aex9)
46+
end
47+
end
48+
end

0 commit comments

Comments
 (0)