123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2020 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openProtocol_client_contextopenProtocolopenAlpha_contextopenTezos_michelinetypeerror+=Contract_has_no_scriptofContract.ttypeerror+=Contract_has_no_storageofContract.ttypeerror+=Entrypoint_mismatchofstring*(Script.expr*Script.expr)optiontypeerror+=Action_unwrapping_errorofstring*Script.exprtypeerror+=Not_a_viewable_entrypointofstringtypeerror+=Not_an_entrypointofScript.exprtypeerror+=Not_enough_balanceofZ.t*Z.ttypeerror+=Not_enough_allowanceofZ.t*Z.ttypeerror+=Unsafe_allowance_changeofZ.ttypeerror+=Unexpected_errorofScript.location*Script.exprletentrypoint_mismatch_explanationppf(name,ty)=matchtywith|None->Format.fprintfppf"Entrypoint %s is missing"name|Some(ty,expected)->Format.fprintfppf"Entrypoint \"%s\" has type @[%a@], but should have type @[%a@]"nameMichelson_v1_printer.print_exprtyMichelson_v1_printer.print_exprexpectedlet()=register_error_kind`Permanent~id:"fa12ContractHasNoScript"~title:"The given contract is not a smart contract"~description:"An FA1.2 command has referenced a scriptless contract."~pp:(funppfcontract->Format.fprintfppf"Contract %a is not a smart contract, it has no script."Contract.ppcontract)Data_encoding.(obj1(req"contract"Contract.encoding))(functionContract_has_no_scriptc->Somec|_->None)(func->Contract_has_no_scriptc);register_error_kind`Permanent~id:"fa12ContractHasNoStorage"~title:"The given contract has no storage"~description:"An FA1.2 command made a call on a contract that has no storage."~pp:(funppfcontract->Format.fprintfppf"Contract %a has no storage."Contract.ppcontract)Data_encoding.(obj1(req"contract"Contract.encoding))(functionContract_has_no_storagec->Somec|_->None)(func->Contract_has_no_storagec);register_error_kind`Permanent~id:"entrypointMismatch"~title:"The given contract does not implement the FA1.2 interface"~description:"An FA1.2 command has referenced a smart contract whose script does not \
implement at least one FA1.2 entrypoint, or with an incompatible type. \
See TZIP-7 \
(https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-7/tzip-7.md) \
for documentation on FA1.2."~pp:(funppf(name,ty)->Format.fprintfppf"Not a supported FA1.2 contract.@\n%a."entrypoint_mismatch_explanation(name,ty))Data_encoding.(obj2(req"name"string)(req"type"(option(tup2Script.expr_encodingScript.expr_encoding))))(functionEntrypoint_mismatch(n,t)->Some(n,t)|_->None)(fun(n,t)->Entrypoint_mismatch(n,t));register_error_kind`Permanent~id:"actionUnwrappingError"~title:"The argument is not for an FA1.2 parameter"~description:"The argument's type does not correspond to that of the corresponding \
FA1.2 entrypoint."~pp:(funppf(entrypoint,expr)->Format.fprintfppf"Not a supported FA1.2 entrypoint argument.@\nEntrypoint: %s@\n%a."entrypointMichelson_v1_printer.print_exprexpr)Data_encoding.(obj2(req"entrypoint"string)(req"expr"Script.expr_encoding))(functionAction_unwrapping_error(s,e)->Some(s,e)|_->None)(fun(s,e)->Action_unwrapping_error(s,e));register_error_kind`Permanent~id:"notAViewableEntrypoint"~title:"The entrypoint is not viewable"~description:"A transaction made a call on an entrypoint expecting it to implement \
the 'view' type."~pp:(funppfentrypoint->Format.fprintfppf"Entrypoint %s is not viewable."entrypoint)Data_encoding.(obj1(req"entrypoint"string))(functionNot_a_viewable_entrypointe->Somee|_->None)(fune->Not_a_viewable_entrypointe);register_error_kind`Permanent~id:"notAnEntrypoint"~title:"The expression is not for an entrypoint"~description:"The parameter value of the contract call refers to a non-existing \
entrypoint."~pp:(funppfparam->Format.fprintfppf"Not a parameter for an entrypoint.@\n%a."Michelson_v1_printer.print_exprparam)Data_encoding.(obj1(req"param"Script.expr_encoding))(functionNot_an_entrypointe->Somee|_->None)(fune->Not_an_entrypointe);register_error_kind`Permanent~id:"notEnoughBalance"~title:"The sender does not have enough balance"~description:"An FA1.2 transfer failed because the sender does not have enough \
balance."~pp:(funppf(required,present)->Format.fprintfppf"Not enough balance.@\nRequired: %a.@\nPresent: %a."Z.pp_printrequiredZ.pp_printpresent)Data_encoding.(obj2(req"present"n)(req"required"n))(functionNot_enough_balance(p,r)->Some(p,r)|_->None)(fun(p,r)->Not_enough_balance(p,r));register_error_kind`Permanent~id:"notEnoughAllowance"~title:"The sender does not have enough allowance"~description:"An FA1.2 transfer failed because the receiver does not have enough \
allowance to ask for a transfer from the sender."~pp:(funppf(required,present)->Format.fprintfppf"Not enough allowance.@\nRequired: %a.@\nPresent: %a."Z.pp_printrequiredZ.pp_printpresent)Data_encoding.(obj2(req"present"n)(req"required"n))(functionNot_enough_allowance(p,r)->Some(p,r)|_->None)(fun(p,r)->Not_enough_allowance(p,r));register_error_kind`Permanent~id:"unsafeAllowanceChange"~title:"The allowance change is unsafe"~description:"An FA1.2 non-zero allowance change failed because the current allowance \
is non-zero. For more explanation on why such allowance change is \
unsafe, please look at TZIP-7 \
(https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-7/tzip-7.md#approve)."~pp:(funppfprevious->Format.fprintfppf"Unsafe allowance change@\nPrevious: %a."Z.pp_printprevious)Data_encoding.(obj1(req"previous"n))(functionUnsafe_allowance_changep->Somep|_->None)(funp->Unsafe_allowance_changep);register_error_kind`Permanent~id:"fa12UnexpectedError"~title:"Unexpected error during FA1.2 contract interpretation"~description:"An unexpected Michelson error was reached during the interpretation of \
an FA1.2 contract."~pp:(funppf(loc,expr)->Format.fprintfppf"An unexpected error was reached at location %d with: %a."locMichelson_v1_printer.print_exprexpr)Data_encoding.(obj2(req"location"Tezos_micheline.Micheline_encoding.canonical_location_encoding)(req"value"Script.expr_encoding))(functionUnexpected_error(loc,expr)->Some(loc,expr)|_->None)(fun(loc,expr)->Unexpected_error(loc,expr))letcallback_encoding=Data_encoding.(conv(fun(c,e)->(c,Option.value~default:""e))(fun(c,e)->(c,ifString.equale""thenNoneelseSomee))(tup2Contract.encodingVariable.string))(** Michelson combinators *)letpair~locab=Micheline.Prim(loc,Script.D_Pair,[a;b],[])letnat~loci=Micheline.Int(loc,i)letunit~loc()=Micheline.Prim(loc,Script.D_Unit,[],[])letbytes~locb=Micheline.Bytes(loc,b)letaddress~locaddr=bytes~loc(Data_encoding.Binary.to_bytes_exnContract.encodingaddr)letcallback~loc?entrypointaddr=bytes~loc(Data_encoding.Binary.to_bytes_exncallback_encoding(addr,entrypoint))(** Types *)(** Michelson type combinators: produce a Michelson node of the
expected type, and a function to check another node is
syntactically equivalent. *)typenode=(Micheline.canonical_location,Michelson_v1_primitives.prim)Micheline.nodetypetype_eq_combinator=node*(node->bool)(** [t_pair ~loc l] takes a list of types and respective equivalence
check functions, and returns a type of n-ary pair of such types and
a function checking syntactical equivalence with another node. *)lett_pair?(loc=0)l:type_eq_combinator=letvalues,are_ty=List.splitlinletis_pairp=matchpwith|Micheline.Prim(_,Script.T_pair,l,_)->(letres=List.for_all2~when_different_lengths:()(funis_tyv->is_tyv)are_tylinmatchreswithOkb->b|Error()->false)|_->falsein(Micheline.Prim(loc,Script.T_pair,values,[]),is_pair)(** [t_unit ~loc ()] returns a Micheline node for the `unit` type, and
a function checking another node is syntactically equivalent. *)lett_unit?(loc=0)():type_eq_combinator=letis_unitp=matchpwithMicheline.Prim(_,Script.T_unit,[],_)->true|_->falsein(Micheline.Prim(loc,Script.T_unit,[],[]),is_unit)(** [t_nat ~loc ()] returns a Micheline node for the `nat` type, and
a function checking another node is syntactically equivalent. *)lett_nat?(loc=0)():type_eq_combinator=letis_natp=matchpwithMicheline.Prim(_,Script.T_nat,[],_)->true|_->falsein(Micheline.Prim(loc,Script.T_nat,[],[]),is_nat)(** [t_address ~loc ()] returns a Micheline node for the `address`
type, and a function checking another node is syntactically
equivalent. *)lett_address?(loc=0)():type_eq_combinator=letis_addressp=matchpwith|Micheline.Prim(_,Script.T_address,[],_)->true|_->falsein(Micheline.Prim(loc,Script.T_address,[],[]),is_address)(** [t_contract ~loc (c, is_c)] takes a node representing a Michelson
type and its own syntactical equivalence checker, and returns a
Micheline node for the type `contract c`, and a function checking
another node is syntactically equivalent. *)lett_contract?(loc=0)(a,is_a):type_eq_combinator=letis_contractc=matchcwith|Micheline.Prim(_,Script.T_contract,[a],_)->is_aa|_->falsein(Micheline.Prim(loc,Script.T_contract,[a],[]),is_contract)(** [t_view ~loc a b] takes two node [a] and [b] and their syntactical
equivalence checking functions, and returns a Micheline node for
the `view a b` type, and a function checking another node is
syntactically equivalent. The view type is defined by
[TZIP4](https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-4/tzip-4.md).
*)lett_view?locab:type_eq_combinator=t_pair?loc[a;t_contract?locb](** * Actions *)(** Corresponds to
[TZIP7](https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-7/tzip-7.md)
entrypoints. *)(** A callback from a view can be on a specific entrypoint of the
contract, or the default one if not specified. *)typecallback_contract=Contract.t*stringoptiontypeaction=|TransferofContract.t*Contract.t*Z.t|ApproveofContract.t*Z.t|Get_allowanceofContract.t*Contract.t*callback_contract|Get_balanceofContract.t*callback_contract|Get_total_supplyofcallback_contractletprint_callback_contractppf(c,etp)=Format.fprintfppf"%a%s"Contract.ppc(matchetpwithNone|Some""->""|Someetp->"%"^etp)letprint_actionppf=function|Transfer(src,dst,amount)->Format.fprintfppf"Transfer (%a, %a, %a)"Contract.ppsrcContract.ppdstZ.pp_printamount|Approve(addr,amount)->Format.fprintfppf"Approve (%a, %a)"Contract.ppaddrZ.pp_printamount|Get_allowance(src,dst,callback)->Format.fprintfppf"Get_allowance (%a, %a, %a)"Contract.ppsrcContract.ppdstprint_callback_contractcallback|Get_balance(addr,callback)->Format.fprintfppf"Get_balance (%a, %a)"Contract.ppaddrprint_callback_contractcallback|Get_total_supplycallback->Format.fprintfppf"Get_total_supply (%a)"print_callback_contractcallbacklettransfer_encoding=Data_encoding.(case~title:"transfer"(Tag0)(obj3(req"transfer_source"Contract.encoding)(req"transfer_destination"Contract.encoding)(req"transfer_amount"n))(function|Transfer(src,dst,amount)->Some(src,dst,amount)|_->None)(fun(src,dst,amount)->Transfer(src,dst,amount)))letapprove_encoding=Data_encoding.(case~title:"approve"(Tag1)(obj2(req"approve_address"Contract.encoding)(req"approve_amount"n))(functionApprove(addr,amount)->Some(addr,amount)|_->None)(fun(addr,amount)->Approve(addr,amount)))letgetBalance_encoding=Data_encoding.(case~title:"getBalance"(Tag2)(obj2(req"getBalance_address"Contract.encoding)(req"getBalance_callback"callback_encoding))(function|Get_balance(addr,callback)->Some(addr,callback)|_->None)(fun(addr,callback)->Get_balance(addr,callback)))letgetAllowance_encoding=Data_encoding.(case~title:"getAllowance"(Tag3)(obj3(req"getAllowance_source"Contract.encoding)(req"getAllowance_destination"Contract.encoding)(req"getAllowance_callback"callback_encoding))(function|Get_allowance(src,dst,callback)->Some(src,dst,callback)|_->None)(fun(src,dst,callback)->Get_allowance(src,dst,callback)))letgetTotalSupply_encoding=Data_encoding.(case~title:"getTotalSupply"(Tag4)(obj1(req"getTotalSupply_callback"callback_encoding))(functionGet_total_supplycallback->Somecallback|_->None)(funcallback->Get_total_supplycallback))letaction_encoding=Data_encoding.union[transfer_encoding;approve_encoding;getBalance_encoding;getAllowance_encoding;getTotalSupply_encoding;]lettransfer_type=t_pair[t_address();t_address();t_nat()]letapprove_type=t_pair[t_address();t_nat()]letgetAllowance_type=t_view(t_pair[t_address();t_address()])(t_nat())letgetBalance_type=t_view(t_address())(t_nat())letgetTotalSupply_type=t_view(t_unit())(t_nat())letstandard_entrypoints=[("transfer",transfer_type);("approve",approve_type);("getAllowance",getAllowance_type);("getBalance",getBalance_type);("getTotalSupply",getTotalSupply_type);]letview_input?(loc=0)action=matchactionwith|Get_allowance(source,destination,_)->pair~loc(address~locsource)(address~locdestination)|Get_balance(addr,_)->address~locaddr|Get_total_supply_->unit~loc()|_->unit~loc()letaction_to_expr?(loc=0)action=matchactionwith|Transfer(source,destination,amount)->pair~loc(address~locsource)(pair~loc(address~locdestination)(nat~locamount))|Approve(addr,amount)->pair~loc(address~locaddr)(nat~locamount)|Get_allowance(_,_,(cb,entrypoint))->letinput=view_inputactioninpair~locinput(callback~loc?entrypointcb)|Get_balance(_,(cb,entrypoint))->letinput=view_inputactioninpair~locinput(callback~loc?entrypointcb)|Get_total_supply(cb,entrypoint)->letinput=view_inputactioninpair~locinput(callback~loc?entrypointcb)letparse_addresserror=function|Micheline.Bytes(_,b)->ok@@Data_encoding.Binary.of_bytes_exnContract.encodingb|String(_,s)->(matchContract.of_b58checkswithOkc->okc|Error_->error())|_->error()letparse_callbackerrorexpr=letof_b58_check(c,entrypoint)=matchContract.of_b58checkcwith|Okc->ok(c,entrypoint)|Error_->error()inmatchexprwith|Micheline.Bytes(_,b)->(matchData_encoding.Binary.of_bytescallback_encodingbwith|Ok(c,entrypoint)->ok(c,entrypoint)|Error_->error())|String(_,s)->(matchString.index_opts'%'with|None->of_b58_check(s,None)|Somepos->(letlen=String.lengths-pos-1inletname=String.subs(pos+1)leninmatch(String.subs0pos,name)with|addr,"default"->of_b58_check(addr,None)|addr,name->of_b58_check(addr,Somename)))|_->error()letaction_of_expr~entrypointexpr=letopenMichelineinleterror()=error(Action_unwrapping_error(entrypoint,Micheline.strip_locationsexpr))inmatch(entrypoint,expr)with(* Transfer operation before comb pairs. *)|("transfer",Prim(_,Script.D_Pair,[((Bytes(_,_)|String(_,_))assource);Prim(_,Script.D_Pair,[((Bytes(_,_)|String(_,_))asdestination);Int(_,amount);],_);],_))(* Transfer operation since Edo comb pairs are now directly interpreted as a
tuple of 3 elements instead of a pair inside a pair. *)|("transfer",Prim(_,Script.D_Pair,[((Bytes(_,_)|String(_,_))assource);((Bytes(_,_)|String(_,_))asdestination);Int(_,amount);],_))->parse_addresserrorsource>>?funsource->parse_addresserrordestination>>?fundestination->ok(Transfer(source,destination,amount))|("approve",Prim(_,Script.D_Pair,[((Bytes(_,_)|String(_,_))asaddr);Int(_,amount)],_))->parse_addresserroraddr>>?funaddr->ok(Approve(addr,amount))|("getBalance",Prim(_,Script.D_Pair,[((Bytes(_,_)|String(_,_))asaddr);((Bytes(_,_)|String(_,_))ascb);],_))->parse_addresserroraddr>>?funaddr->parse_callbackerrorcb>>?funcallback->ok(Get_balance(addr,callback))|("getAllowance",Prim(_,Script.D_Pair,[Prim(_,Script.D_Pair,[((Bytes(_,_)|String(_,_))assource);((Bytes(_,_)|String(_,_))asdestination);],_);((Bytes(_,_)|String(_,_))ascontract);],_))->parse_addresserrorsource>>?funsource->parse_addresserrordestination>>?fundestination->parse_callbackerrorcontract>>?funcallback->ok(Get_allowance(source,destination,callback))|("getTotalSupply",Prim(_,Script.D_Pair,[Prim(_,Script.D_Unit,[],_);((Bytes(_,_)|String(_,_))ascontract);],_))->parse_callbackerrorcontract>>?funcallback->ok(Get_total_supplycallback)|_->error()letfind_entrypoint_in_annoterrorannotsexpr=matchList.find_opt(funannot->annot.[0]='%')annotswith|Someentrypoint->action_of_expr~entrypoint:(String.subentrypoint1(String.lengthentrypoint-1))expr|None->error()letderive_actionexprt_param=leterror()=error(Not_an_entrypoint(Micheline.strip_locationsexpr))inletrecderiveexprt_param=match(expr,t_param)with|(Micheline.Prim(_,Script.D_Left,[left],_),Micheline.Prim(_,Script.T_or,[t_left;_],_))->deriveleftt_left|(Micheline.Prim(_,Script.D_Right,[right],_),Micheline.Prim(_,Script.T_or,[_;t_right],_))->deriverightt_right|_,Micheline.Prim(_,_,_,annots)->find_entrypoint_in_annoterrorannotsexpr|_->error()inderiveexprt_paramletextract_parametercontract=function|Micheline.Seq(_,l)->(List.filter_map(function|Micheline.Prim(_,Script.K_parameter,[param],_)->Someparam|_->None)l|>function|param::_->okparam|_->error(Contract_has_no_scriptcontract))|_->error(Contract_has_no_scriptcontract)letget_contract_parametercctxt~chain~blockcontract=Client_proto_context.get_scriptcctxt~chain~blockcontract>>=?function|None->fail(Contract_has_no_scriptcontract)|Some{code;_}->(matchScript_repr.force_decodecodewith|Error_->fail(Contract_has_no_scriptcontract)|Ok(code,_)->Lwt.return(extract_parametercontract(Micheline.rootcode)))letconvert_wrapped_parameter_into_actioncctxt~chain~blockcontractparam=get_contract_parametercctxt~chain~blockcontract>>=?funparameter->Lwt.return(derive_actionparamparameter)letcheck_entrypointentrypoints(name,(expected_ty,check))=matchList.assoc_opt~equal:String.equalnameentrypointswith|None->error(Entrypoint_mismatch(name,None))|Somety->ifnot(check(Micheline.rootty))thenerror(Entrypoint_mismatch(name,Some(ty,Micheline.strip_locationsexpected_ty)))elseOk()letaction_to_entrypoint=function|Transfer(_,_,_)->"transfer"|Approve(_,_)->"approve"|Get_allowance(_,_,_)->"getAllowance"|Get_balance(_,_)->"getBalance"|Get_total_supply_->"getTotalSupply"letcontract_has_fa12_interface:#Protocol_client_context.rpc_context->chain:Shell_services.chain->block:Shell_services.block->contract:Alpha_context.Contract.t->unit->unittzresultLwt.t=funcctxt~chain~block~contract()->matchContract.is_implicitcontractwith|Some_->fail(Contract_has_no_scriptcontract)|None->Michelson_v1_entrypoints.list_contract_entrypointscctxt~chain~block~contract>>=?funentrypoints->List.iter_e(check_entrypointentrypoints)standard_entrypoints|>Lwt.returnlettranslate_action_to_argumentaction=letentrypoint=action_to_entrypointactioninletexpr=Micheline.strip_locations(action_to_expraction)in(entrypoint,Format.asprintf"%a"Michelson_v1_printer.print_exprexpr)letparse_error=letopenMichelineinfunction|("NotEnoughBalance",Prim(_,Script.D_Pair,[Int(_,required);Int(_,present)],_))->Some(Not_enough_balance(required,present))|("NotEnoughAllowance",Prim(_,Script.D_Pair,[Int(_,required);Int(_,present)],_))->Some(Not_enough_allowance(required,present))|"UnsafeAllowanceChange",Int(_,previous)->Some(Unsafe_allowance_changeprevious)|_->Noneletextract_errortrace=letopenMichelineinTzTrace.fold(fun_error->matcherrorwith|Environment.Ecoproto_error(Script_interpreter.Reject(loc,param,_))->(matchrootparamwith|Prim(_,Script.D_Pair,[String(_,error);res],_)->parse_error(error,res)|_->Some(Unexpected_error(loc,param)))|_->None)Nonetraceletcall_contract(cctxt:#Protocol_client_context.full)~chain~block?confirmations?dry_run?verbose_signing?branch~source~src_pk~src_sk~contract~action~tez_amount?fee?gas_limit?storage_limit?counter~fee_parameter()=contract_has_fa12_interfacecctxt~chain~block~contract()>>=?fun()->letentrypoint,arg=translate_action_to_argumentactioninClient_proto_context.transfercctxt~chain~block?confirmations?dry_run?branch~source~src_pk~src_sk~destination:contract~arg~amount:tez_amount~entrypoint?fee?gas_limit?storage_limit?counter~fee_parameter?verbose_signing()>>=function|Okres->returnres|Errortrace->(matchextract_errortracewith|None->Lwt.return(Errortrace)|Someerror->failerror)typetoken_transfer={token_contract:string;destination:string;amount:Z.t;tez_amount:stringoption;fee:stringoption;gas_limit:Gas.Arith.integraloption;storage_limit:Z.toption;}lettoken_transfer_encoding=letopenData_encodinginconv(fun{token_contract;destination;amount;tez_amount;fee;gas_limit;storage_limit;}->(token_contract,destination,amount,tez_amount,fee,gas_limit,storage_limit))(fun(token_contract,destination,amount,tez_amount,fee,gas_limit,storage_limit)->{token_contract;destination;amount;tez_amount;fee;gas_limit;storage_limit;})(obj7(req"token_contract"string)(req"destination"string)(req"amount"z)(opt"tez-amount"string)(opt"fee"string)(opt"gas-limit"Gas.Arith.n_integral_encoding)(opt"storage-limit"z))lettez_of_string_exnindexfields=matchTez.of_stringswith|Somet->okt|None->error_with"Invalid %s notation at entry %i, field \"%s\": %s"Client_proto_args.tez_symindexfieldslettez_of_opt_string_exnindexfields=Option.map_e(tez_of_string_exnindexfield)sletbuild_transaction_operation?(tez_amount=Tez.zero)?fee?gas_limit?storage_limittokenaction=letentrypoint=action_to_entrypointactioninletparameters=Script.lazy_expr(Micheline.strip_locations(action_to_expraction))inletoperation=Transaction{amount=tez_amount;parameters;destination=token;entrypoint}inInjection.prepare_manager_operation?fee?gas_limit?storage_limitoperationletprepare_single_token_transfercctxt?default_fee?default_gas_limit?default_storage_limit~chain~blocksrcindextransfer=Client_proto_contracts.Contract_alias.find_destinationcctxttransfer.token_contract>>=?fun(_,token)->contract_has_fa12_interfacecctxt~chain~block~contract:token()>>=?fun()->Client_proto_contracts.Contract_alias.find_destinationcctxttransfer.destination>>=?fun(_,dest)->tez_of_opt_string_exnindex"tez_amount"transfer.tez_amount>>?=funtez_amount->tez_of_opt_string_exnindex"fee"transfer.fee>>?=funtransfer_fee->letfee=Option.eithertransfer_feedefault_feeinletgas_limit=Option.eithertransfer.gas_limitdefault_gas_limitinletstorage_limit=Option.eithertransfer.storage_limitdefault_storage_limitinletaction=Transfer(src,dest,transfer.amount)inletoperation=build_transaction_operation?tez_amount?fee?gas_limit?storage_limittokenactioninreturn(Injection.Annotated_manager_operationoperation)letinject_token_transfer_batch(cctxt:#Protocol_client_context.full)~chain~block?confirmations?dry_run?verbose_signing~sender~source~src_pk~src_sk~token_transfers~fee_parameter?counter?default_fee?default_gas_limit?default_storage_limit()=List.mapi_ep(prepare_single_token_transfercctxt?default_fee?default_gas_limit?default_storage_limit~chain~blocksender)token_transfers>>=?funcontents->let(Manager_listcontents)=Injection.manager_of_listcontentsinInjection.inject_manager_operationcctxt~chain~block?confirmations?dry_run?verbose_signing~source?fee:default_fee?gas_limit:default_gas_limit?storage_limit:default_storage_limit?counter~src_pk~src_sk~fee_parametercontents>>=function|Ok_->return()|Errortrace->(matchextract_errortracewith|None->Lwt.return(Errortrace)|Someerror->failerror)letis_viewable_actionaction=matchactionwith|Get_balance(_,_)|Get_allowance(_,_,_)|Get_total_supply_->return()|_->fail(Not_a_viewable_entrypoint(action_to_entrypointaction))letrun_view_action(cctxt:#Protocol_client_context.full)~chain~block?source~contract~action?payer?gas~unparsing_mode()=is_viewable_actionaction>>=?fun()->contract_has_fa12_interfacecctxt~chain~block~contract()>>=?fun()->letentrypoint=action_to_entrypointactioninletinput=Micheline.strip_locations(view_inputaction)inChain_services.chain_idcctxt~chain()>>=?funchain_id->Plugin.RPC.run_viewcctxt(chain,block)~contract~input~chain_id~source~payer?gas~entrypoint~unparsing_modelet()=Data_encoding.(Registration.register@@def(Protocol.name^".fa1.2.token_transfer")token_transfer_encoding)