Add Address.to_contract
Casts an address to a (any) contract type.
This commit is contained in:
parent
7f86b7d301
commit
5fc6e18cd2
@ -60,7 +60,8 @@
|
|||||||
|
|
||||||
-record(is_contract_constraint,
|
-record(is_contract_constraint,
|
||||||
{ contract_t :: utype(),
|
{ contract_t :: utype(),
|
||||||
context :: aeso_syntax:expr() %% The address literal
|
context :: {contract_literal, aeso_syntax:expr()} |
|
||||||
|
{address_to_contract, aeso_syntax:ann()}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-type field_constraint() :: #field_constraint{} | #record_create_constraint{} | #is_contract_constraint{}.
|
-type field_constraint() :: #field_constraint{} | #record_create_constraint{} | #is_contract_constraint{}.
|
||||||
@ -83,7 +84,7 @@
|
|||||||
-type qname() :: [string()].
|
-type qname() :: [string()].
|
||||||
-type typesig() :: {type_sig, aeso_syntax:ann(), type_constraints(), [aeso_syntax:named_arg_t()], [type()], type()}.
|
-type typesig() :: {type_sig, aeso_syntax:ann(), type_constraints(), [aeso_syntax:named_arg_t()], [type()], type()}.
|
||||||
|
|
||||||
-type type_constraints() :: none | bytes_concat | bytes_split.
|
-type type_constraints() :: none | bytes_concat | bytes_split | address_to_contract.
|
||||||
|
|
||||||
-type fun_info() :: {aeso_syntax:ann(), typesig() | type()}.
|
-type fun_info() :: {aeso_syntax:ann(), typesig() | type()}.
|
||||||
-type type_info() :: {aeso_syntax:ann(), typedef()}.
|
-type type_info() :: {aeso_syntax:ann(), typedef()}.
|
||||||
@ -519,6 +520,7 @@ global_env() ->
|
|||||||
%% Conversion
|
%% Conversion
|
||||||
IntScope = #scope{ funs = MkDefs([{"to_str", Fun1(Int, String)}]) },
|
IntScope = #scope{ funs = MkDefs([{"to_str", Fun1(Int, String)}]) },
|
||||||
AddressScope = #scope{ funs = MkDefs([{"to_str", Fun1(Address, String)},
|
AddressScope = #scope{ funs = MkDefs([{"to_str", Fun1(Address, String)},
|
||||||
|
{"to_contract", FunC(address_to_contract, [Address], A)},
|
||||||
{"is_oracle", Fun1(Address, Bool)},
|
{"is_oracle", Fun1(Address, Bool)},
|
||||||
{"is_contract", Fun1(Address, Bool)},
|
{"is_contract", Fun1(Address, Bool)},
|
||||||
{"is_payable", Fun1(Address, Bool)}]) },
|
{"is_payable", Fun1(Address, Bool)}]) },
|
||||||
@ -1081,7 +1083,7 @@ infer_expr(_Env, Body={oracle_query_id, As, _}) ->
|
|||||||
infer_expr(_Env, Body={contract_pubkey, As, _}) ->
|
infer_expr(_Env, Body={contract_pubkey, As, _}) ->
|
||||||
Con = fresh_uvar(As),
|
Con = fresh_uvar(As),
|
||||||
constrain([#is_contract_constraint{ contract_t = Con,
|
constrain([#is_contract_constraint{ contract_t = Con,
|
||||||
context = Body }]),
|
context = {contract_literal, Body} }]),
|
||||||
{typed, As, Body, Con};
|
{typed, As, Body, Con};
|
||||||
infer_expr(_Env, Body={id, As, "_"}) ->
|
infer_expr(_Env, Body={id, As, "_"}) ->
|
||||||
{typed, As, Body, fresh_uvar(As)};
|
{typed, As, Body, fresh_uvar(As)};
|
||||||
@ -1653,11 +1655,11 @@ check_record_create_constraints(Env, [C | Cs]) ->
|
|||||||
|
|
||||||
check_is_contract_constraints(_Env, []) -> ok;
|
check_is_contract_constraints(_Env, []) -> ok;
|
||||||
check_is_contract_constraints(Env, [C | Cs]) ->
|
check_is_contract_constraints(Env, [C | Cs]) ->
|
||||||
#is_contract_constraint{ contract_t = Type, context = Lit } = C,
|
#is_contract_constraint{ contract_t = Type, context = Cxt } = C,
|
||||||
Type1 = unfold_types_in_type(Env, instantiate(Type)),
|
Type1 = unfold_types_in_type(Env, instantiate(Type)),
|
||||||
case lookup_type(Env, record_type_name(Type1)) of
|
case lookup_type(Env, record_type_name(Type1)) of
|
||||||
{_, {_Ann, {[], {contract_t, _}}}} -> ok;
|
{_, {_Ann, {[], {contract_t, _}}}} -> ok;
|
||||||
_ -> type_error({not_a_contract_type, Type1, Lit})
|
_ -> type_error({not_a_contract_type, Type1, Cxt})
|
||||||
end,
|
end,
|
||||||
check_is_contract_constraints(Env, Cs).
|
check_is_contract_constraints(Env, Cs).
|
||||||
|
|
||||||
@ -2078,6 +2080,9 @@ freshen_type_sig(Ann, TypeSig = {type_sig, _, Constr, _, _, _}) ->
|
|||||||
FunT.
|
FunT.
|
||||||
|
|
||||||
apply_typesig_constraint(_Ann, none, _FunT) -> ok;
|
apply_typesig_constraint(_Ann, none, _FunT) -> ok;
|
||||||
|
apply_typesig_constraint(Ann, address_to_contract, {fun_t, _, [], [_], Type}) ->
|
||||||
|
constrain([#is_contract_constraint{ contract_t = Type,
|
||||||
|
context = {address_to_contract, Ann}}]);
|
||||||
apply_typesig_constraint(Ann, bytes_concat, {fun_t, _, [], [A, B], C}) ->
|
apply_typesig_constraint(Ann, bytes_concat, {fun_t, _, [], [A, B], C}) ->
|
||||||
add_bytes_constraint({add_bytes, Ann, concat, A, B, C});
|
add_bytes_constraint({add_bytes, Ann, concat, A, B, C});
|
||||||
apply_typesig_constraint(Ann, bytes_split, {fun_t, _, [], [C], {tuple_t, _, [A, B]}}) ->
|
apply_typesig_constraint(Ann, bytes_split, {fun_t, _, [], [C], {tuple_t, _, [A, B]}}) ->
|
||||||
@ -2176,12 +2181,28 @@ mk_error({not_a_record_type, Type, Why}) ->
|
|||||||
Msg = io_lib:format("~s\n", [pp_type("Not a record type: ", Type)]),
|
Msg = io_lib:format("~s\n", [pp_type("Not a record type: ", Type)]),
|
||||||
{Pos, Ctxt} = pp_why_record(Why),
|
{Pos, Ctxt} = pp_why_record(Why),
|
||||||
mk_t_err(Pos, Msg, Ctxt);
|
mk_t_err(Pos, Msg, Ctxt);
|
||||||
mk_error({not_a_contract_type, Type, Lit}) ->
|
mk_error({not_a_contract_type, Type, Cxt}) ->
|
||||||
Msg = io_lib:format("The type ~s is not a contract type\n"
|
Msg =
|
||||||
"when checking that the contract literal at ~s\n~s\n"
|
case Type of
|
||||||
"has the type\n~s\n",
|
{tvar, _, _} ->
|
||||||
[pp_type("", Type), pp_loc(Lit), pp_expr(" ", Lit), pp_type(" ", Type)]),
|
"Unresolved contract type\n";
|
||||||
mk_t_err(pos(Lit), Msg);
|
_ ->
|
||||||
|
io_lib:format("The type ~s is not a contract type\n", [pp_type("", Type)])
|
||||||
|
end,
|
||||||
|
{Pos, Cxt1} =
|
||||||
|
case Cxt of
|
||||||
|
{contract_literal, Lit} ->
|
||||||
|
{pos(Lit),
|
||||||
|
io_lib:format("when checking that the contract literal\n~s\n"
|
||||||
|
"has the type\n~s\n",
|
||||||
|
[pp_expr(" ", Lit), pp_type(" ", Type)])};
|
||||||
|
{address_to_contract, Ann} ->
|
||||||
|
{pos(Ann),
|
||||||
|
io_lib:format("when checking that the call to\n Address.to_contract\n"
|
||||||
|
"has the type\n~s\n",
|
||||||
|
[pp_type(" ", Type)])}
|
||||||
|
end,
|
||||||
|
mk_t_err(Pos, Msg, Cxt1);
|
||||||
mk_error({non_linear_pattern, Pattern, Nonlinear}) ->
|
mk_error({non_linear_pattern, Pattern, Nonlinear}) ->
|
||||||
Msg = io_lib:format("Repeated name~s ~s in pattern\n~s (at ~s)\n",
|
Msg = io_lib:format("Repeated name~s ~s in pattern\n~s (at ~s)\n",
|
||||||
[plural("", "s", Nonlinear), string:join(Nonlinear, ", "),
|
[plural("", "s", Nonlinear), string:join(Nonlinear, ", "),
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
map_delete | map_member | map_size | string_length |
|
map_delete | map_member | map_size | string_length |
|
||||||
string_concat | bits_set | bits_clear | bits_test | bits_sum |
|
string_concat | bits_set | bits_clear | bits_test | bits_sum |
|
||||||
bits_intersection | bits_union | bits_difference |
|
bits_intersection | bits_union | bits_difference |
|
||||||
contract_to_address | crypto_verify_sig | crypto_verify_sig_secp256k1 |
|
contract_to_address | address_to_contract | crypto_verify_sig | crypto_verify_sig_secp256k1 |
|
||||||
crypto_sha3 | crypto_sha256 | crypto_blake2b |
|
crypto_sha3 | crypto_sha256 | crypto_blake2b |
|
||||||
crypto_ecverify_secp256k1 | crypto_ecrecover_secp256k1.
|
crypto_ecverify_secp256k1 | crypto_ecrecover_secp256k1.
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ builtins() ->
|
|||||||
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
||||||
{["Bytes"], [{"to_int", 1}, {"to_str", 1}, {"concat", 2}, {"split", 1}]},
|
{["Bytes"], [{"to_int", 1}, {"to_str", 1}, {"concat", 2}, {"split", 1}]},
|
||||||
{["Int"], [{"to_str", 1}]},
|
{["Int"], [{"to_str", 1}]},
|
||||||
{["Address"], [{"to_str", 1}, {"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]}
|
{["Address"], [{"to_str", 1}, {"to_contract", 1}, {"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]}
|
||||||
],
|
],
|
||||||
maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}}
|
maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}}
|
||||||
|| {NS, Funs} <- Scopes,
|
|| {NS, Funs} <- Scopes,
|
||||||
@ -904,6 +904,7 @@ op_builtins() ->
|
|||||||
string_length, string_concat, string_sha3, string_sha256, string_blake2b,
|
string_length, string_concat, string_sha3, string_sha256, string_blake2b,
|
||||||
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
||||||
bits_difference, int_to_str, address_to_str, crypto_verify_sig,
|
bits_difference, int_to_str, address_to_str, crypto_verify_sig,
|
||||||
|
address_to_contract,
|
||||||
crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b,
|
crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b,
|
||||||
crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1
|
crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1
|
||||||
].
|
].
|
||||||
|
@ -494,6 +494,7 @@ is_builtin_fun({qid, _, ["Address", "to_str"]}, _Icode) ->
|
|||||||
is_builtin_fun({qid, _, ["Address", "is_oracle"]}, _Icode) -> true;
|
is_builtin_fun({qid, _, ["Address", "is_oracle"]}, _Icode) -> true;
|
||||||
is_builtin_fun({qid, _, ["Address", "is_contract"]}, _Icode) -> true;
|
is_builtin_fun({qid, _, ["Address", "is_contract"]}, _Icode) -> true;
|
||||||
is_builtin_fun({qid, _, ["Address", "is_payable"]}, _Icode) -> true;
|
is_builtin_fun({qid, _, ["Address", "is_payable"]}, _Icode) -> true;
|
||||||
|
is_builtin_fun({qid, _, ["Address", "to_contract"]}, _Icode) -> true;
|
||||||
is_builtin_fun({qid, _, ["Bytes", "to_int"]}, _Icode) -> true;
|
is_builtin_fun({qid, _, ["Bytes", "to_int"]}, _Icode) -> true;
|
||||||
is_builtin_fun({qid, _, ["Bytes", "to_str"]}, _Icode) -> true;
|
is_builtin_fun({qid, _, ["Bytes", "to_str"]}, _Icode) -> true;
|
||||||
is_builtin_fun({qid, _, ["Bytes", "concat"]}, _Icode) -> true;
|
is_builtin_fun({qid, _, ["Bytes", "concat"]}, _Icode) -> true;
|
||||||
@ -713,6 +714,8 @@ builtin_code(_, {qid, _, ["Address", "is_contract"]}, [Addr], _, _, Icode) ->
|
|||||||
builtin_code(_, {qid, _, ["Address", "is_payable"]}, [Addr], _, _, Icode) ->
|
builtin_code(_, {qid, _, ["Address", "is_payable"]}, [Addr], _, _, Icode) ->
|
||||||
prim_call(?PRIM_CALL_ADDR_IS_PAYABLE, #integer{value = 0},
|
prim_call(?PRIM_CALL_ADDR_IS_PAYABLE, #integer{value = 0},
|
||||||
[ast_body(Addr, Icode)], [word], word);
|
[ast_body(Addr, Icode)], [word], word);
|
||||||
|
builtin_code(_, {qid, _, ["Address", "to_contract"]}, [Addr], _, _, Icode) ->
|
||||||
|
ast_body(Addr, Icode);
|
||||||
|
|
||||||
builtin_code(_, {qid, _, ["Bytes", "to_int"]}, [Bytes], _, _, Icode) ->
|
builtin_code(_, {qid, _, ["Bytes", "to_int"]}, [Bytes], _, _, Icode) ->
|
||||||
{typed, _, _, {bytes_t, _, N}} = Bytes,
|
{typed, _, _, {bytes_t, _, N}} = Bytes,
|
||||||
|
@ -103,6 +103,7 @@
|
|||||||
Op =:= 'ECVERIFY_SECP256K1' orelse
|
Op =:= 'ECVERIFY_SECP256K1' orelse
|
||||||
Op =:= 'ECRECOVER_SECP256K1' orelse
|
Op =:= 'ECRECOVER_SECP256K1' orelse
|
||||||
Op =:= 'CONTRACT_TO_ADDRESS' orelse
|
Op =:= 'CONTRACT_TO_ADDRESS' orelse
|
||||||
|
Op =:= 'ADDRESS_TO_CONTRACT' orelse
|
||||||
Op =:= 'AUTH_TX_HASH' orelse
|
Op =:= 'AUTH_TX_HASH' orelse
|
||||||
Op =:= 'BYTES_TO_INT' orelse
|
Op =:= 'BYTES_TO_INT' orelse
|
||||||
Op =:= 'BYTES_TO_STR' orelse
|
Op =:= 'BYTES_TO_STR' orelse
|
||||||
@ -611,6 +612,7 @@ op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a);
|
|||||||
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
||||||
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
||||||
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
||||||
|
op_to_scode(address_to_contract) -> aeb_fate_ops:address_to_contract(?a, ?a);
|
||||||
op_to_scode(crypto_verify_sig) -> aeb_fate_ops:verify_sig(?a, ?a, ?a, ?a);
|
op_to_scode(crypto_verify_sig) -> aeb_fate_ops:verify_sig(?a, ?a, ?a, ?a);
|
||||||
op_to_scode(crypto_verify_sig_secp256k1) -> aeb_fate_ops:verify_sig_secp256k1(?a, ?a, ?a, ?a);
|
op_to_scode(crypto_verify_sig_secp256k1) -> aeb_fate_ops:verify_sig_secp256k1(?a, ?a, ?a, ?a);
|
||||||
op_to_scode(crypto_ecverify_secp256k1) -> aeb_fate_ops:ecverify_secp256k1(?a, ?a, ?a, ?a);
|
op_to_scode(crypto_ecverify_secp256k1) -> aeb_fate_ops:ecverify_secp256k1(?a, ?a, ?a, ?a);
|
||||||
@ -851,6 +853,7 @@ attributes(I) ->
|
|||||||
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
{'ECRECOVER_SECP256K1', A, B, C} -> Pure(A, [B, C]);
|
{'ECRECOVER_SECP256K1', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
||||||
|
{'ADDRESS_TO_CONTRACT', A, B} -> Pure(A, [B]);
|
||||||
{'AUTH_TX_HASH', A} -> Pure(A, []);
|
{'AUTH_TX_HASH', A} -> Pure(A, []);
|
||||||
{'BYTES_TO_INT', A, B} -> Pure(A, [B]);
|
{'BYTES_TO_INT', A, B} -> Pure(A, [B]);
|
||||||
{'BYTES_TO_STR', A, B} -> Pure(A, [B]);
|
{'BYTES_TO_STR', A, B} -> Pure(A, [B]);
|
||||||
|
@ -356,19 +356,19 @@ failing_contracts() ->
|
|||||||
, ?TYPE_ERROR(bad_address_literals,
|
, ?TYPE_ERROR(bad_address_literals,
|
||||||
[<<?Pos(32, 5)
|
[<<?Pos(32, 5)
|
||||||
"The type bytes(32) is not a contract type\n"
|
"The type bytes(32) is not a contract type\n"
|
||||||
"when checking that the contract literal at line 32, column 5\n"
|
"when checking that the contract literal\n"
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
"has the type\n"
|
"has the type\n"
|
||||||
" bytes(32)">>,
|
" bytes(32)">>,
|
||||||
<<?Pos(30, 5)
|
<<?Pos(30, 5)
|
||||||
"The type oracle(int, bool) is not a contract type\n"
|
"The type oracle(int, bool) is not a contract type\n"
|
||||||
"when checking that the contract literal at line 30, column 5\n"
|
"when checking that the contract literal\n"
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
"has the type\n"
|
"has the type\n"
|
||||||
" oracle(int, bool)">>,
|
" oracle(int, bool)">>,
|
||||||
<<?Pos(28, 5)
|
<<?Pos(28, 5)
|
||||||
"The type address is not a contract type\n"
|
"The type address is not a contract type\n"
|
||||||
"when checking that the contract literal at line 28, column 5\n"
|
"when checking that the contract literal\n"
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
"has the type\n"
|
"has the type\n"
|
||||||
" address">>,
|
" address">>,
|
||||||
@ -440,7 +440,13 @@ failing_contracts() ->
|
|||||||
"when checking the type of the expression at line 7, column 5\n"
|
"when checking the type of the expression at line 7, column 5\n"
|
||||||
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" bytes(32)">>])
|
" bytes(32)">>,
|
||||||
|
<<?Pos(34, 5),
|
||||||
|
"The type address is not a contract type\n"
|
||||||
|
"when checking that the call to\n"
|
||||||
|
" Address.to_contract\n"
|
||||||
|
"has the type\n"
|
||||||
|
" address">>])
|
||||||
, ?TYPE_ERROR(stateful,
|
, ?TYPE_ERROR(stateful,
|
||||||
[<<?Pos(13, 35)
|
[<<?Pos(13, 35)
|
||||||
"Cannot reference stateful function Chain.spend (at line 13, column 35)\nin the definition of non-stateful function fail1.">>,
|
"Cannot reference stateful function Chain.spend (at line 13, column 35)\nin the definition of non-stateful function fail1.">>,
|
||||||
|
@ -11,4 +11,6 @@ contract AddressLiterals =
|
|||||||
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
|
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
|
||||||
entrypoint contr() : Remote =
|
entrypoint contr() : Remote =
|
||||||
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
|
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
|
||||||
|
entrypoint contr_addr() : Remote =
|
||||||
|
Address.to_contract(addr())
|
||||||
|
|
||||||
|
@ -30,4 +30,6 @@ contract AddressLiterals =
|
|||||||
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
|
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
|
||||||
entrypoint contr3() : bytes(32) =
|
entrypoint contr3() : bytes(32) =
|
||||||
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
|
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
|
||||||
|
entrypoint contr4() : address =
|
||||||
|
Address.to_contract(Contract.address)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user