diff --git a/contract/.ligo/repository_id b/contract/.ligo/repository_id new file mode 100644 index 0000000..51df288 --- /dev/null +++ b/contract/.ligo/repository_id @@ -0,0 +1 @@ +1501d5bc-639e-46f4-20d5-72c9862ee606 \ No newline at end of file diff --git a/contract/README.md b/contract/README.md index a9dcd61..95f37ea 100644 --- a/contract/README.md +++ b/contract/README.md @@ -1,24 +1,24 @@ # Contract -## Compile contract (to check any error, and prepare the michelson outputfile to deploy later) +## Compile contract (to check any error, and prepare the michelson outputfile to deploy later) ```bash -ligo compile contract ./src/contract.jsligo --output-file contract.tz --protocol kathmandu +ligo compile contract ./src/contract.jsligo --output-file contract.tz --protocol nairobi -ligo compile storage ./src/contract.jsligo '{treasuryAddress : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address,faPendingDeposits : Map.empty as faPendingMapType, faPendingWithdrawals : Map.empty as faPendingMapType}' --output-file contractStorage.tz --protocol kathmandu +ligo compile storage ./src/contract.jsligo '{treasuryAddress : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address,faPendingDeposits : Map.empty as faPendingMapType, faPendingWithdrawals : Map.empty as faPendingMapType}' --output-file contractStorage.tz --protocol nairobi ``` ## Deploy ```bash -tezos-client originate contract tzportalKathmandu transferring 0 from myFirstKey running contract.tz --init "$(cat contractStorage.tz)" --burn-cap 1 --force +tezos-client originate contract tzportalNairobi transferring 0 from myFirstKey running contract.tz --init "$(cat contractStorage.tz)" --burn-cap 1 --force ``` - Jakarta : KT1WknoW9XN6ZpvsnMmsuPZ6tvTkF4FqYCQ6 - Ghostnet : KT1QvZPUoXwz5zQL6zDpFyyPp5iChbHfnXC1 -- Kathmandunet : KT1E8QEK4tkm1P3FRrm66hzX8zpDshBth5Lu +- Nairobinet : KT1E8QEK4tkm1P3FRrm66hzX8zpDshBth5Lu -## Run tests +## Run tests ```bash ligo run test ./test/unit_contract.jsligo @@ -27,10 +27,10 @@ ligo run test ./test/unit_contract.jsligo ## Interact ```bash -ligo compile parameter ./src/contract.jsligo 'Deposit(XTZ_OP({amountToTransfer : 42000000 as nat,l2Address : L1_ADDRESS("tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address) ,rollupAddress : "KT1TLVFbGtkX6bS9tUKmRGPqGtf1K6SGgqXK" as address}))' --output-file contractParameter.tz --protocol kathmandu +ligo compile parameter ./src/contract.jsligo 'Deposit(XTZ_OP({amountToTransfer : 42000000 as nat,l2Address : L1_ADDRESS("tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address) ,rollupAddress : "KT1TLVFbGtkX6bS9tUKmRGPqGtf1K6SGgqXK" as address}))' --output-file contractParameter.tz --protocol nairobi (or FA1.2 -ligo compile parameter ./src/contract.jsligo 'Deposit(FA12_OP({amountToTransfer : 1 as nat,fa12Address : "KT1WnDswMHZefo2fym6Q9c8hnL3sEuzFb2Dt" as address,l2Address : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address,rollupAddress : "txr1Q4iYZti8wfKXJi9CyagSnAHCogzX877kD" as address}))' --output-file contractParameter.tz --protocol kathmandu +ligo compile parameter ./src/contract.jsligo 'Deposit(FA12_OP({amountToTransfer : 1 as nat,fa12Address : "KT1WnDswMHZefo2fym6Q9c8hnL3sEuzFb2Dt" as address,l2Address : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address,rollupAddress : "txr1Q4iYZti8wfKXJi9CyagSnAHCogzX877kD" as address}))' --output-file contractParameter.tz --protocol nairobi ) @@ -41,57 +41,71 @@ tezos-client transfer 42 from myFirstKey to KT1Ci5heqWbRmxM98769W7jqVxCZ9zZUQ31o ## Ctez -ligo compile contract ./test/fa12.mligo --entry-point main --output-file ./test/fa12.tz --protocol kathmandu +ligo compile contract ./test/fa12.mligo --entry-point main --output-file ./test/fa12.tz --protocol nairobi -ligo compile storage ./test/fa12.mligo "$(cat ./test/fa12_ctez_storage.mligo)" --entry-point main --output-file ./test/fa12_ctez_storage.tz --protocol kathmandu +ligo compile storage ./test/fa12.mligo "$(cat ./test/fa12_ctez_storage.mligo)" --entry-point main --output-file ./test/fa12_ctez_storage.tz --protocol nairobi -tezos-client originate contract fa12CTEZKathmandunet transferring 0 from alice running ./test/fa12.tz --init "$(cat ./test/fa12_ctez_storage.tz)" --burn-cap 1 --force +tezos-client originate contract fa12CTEZNairobinet transferring 0 from alice running ./test/fa12.tz --init "$(cat ./test/fa12_ctez_storage.tz)" --burn-cap 1 --force ## kusd -ligo compile contract ./test/fa12.mligo --entry-point main --output-file ./test/fa12.tz --protocol kathmandu +ligo compile contract ./test/fa12.mligo --entry-point main --output-file ./test/fa12.tz --protocol nairobi -ligo compile storage ./test/fa12.mligo "$(cat ./test/fa12_kusd_storage.mligo)" --entry-point main --output-file ./test/fa12_kusd_storage.tz --protocol kathmandu +ligo compile storage ./test/fa12.mligo "$(cat ./test/fa12_kusd_storage.mligo)" --entry-point main --output-file ./test/fa12_kusd_storage.tz --protocol nairobi -tezos-client originate contract fa12KUSDKathmandunet transferring 0 from alice running ./test/fa12.tz --init "$(cat ./test/fa12_kusd_storage.tz)" --burn-cap 1 --force +tezos-client originate contract fa12KUSDNairobinet transferring 0 from alice running ./test/fa12.tz --init "$(cat ./test/fa12_kusd_storage.tz)" --burn-cap 1 --force # FA2 Contract -### uUSD +### uUSD -ligo compile contract ./test/fa2.jsligo --entry-point main --output-file ./test/fa2.tz --protocol kathmandu +ligo compile contract ./test/fa2.jsligo --output-file ./test/fa2.tz --protocol nairobi -ligo compile storage ./test/fa2.jsligo "$(cat ./test/fa2_uUSD_storage.jsligo)" --entry-point main --output-file ./test/fa2_uUSD_storage.tz --protocol kathmandu +ligo compile storage ./test/fa2.jsligo "$(cat ./test/fa2_uUSD_storage.jsligo)" --output-file ./test/fa2_uUSD_storage.tz --protocol nairobi -ligo compile parameter ./test/fa2.jsligo 'Transfer(list([{ from_ : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address, tx : list([ { to_ : "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" as address, token_id : 0 as nat, quantity : 10000000000 as nat } ]) as list }]))' --output-file ./test/fa2Parameter.tz --protocol kathmandu +``` +ligo compile parameter ./test/fa2.jsligo 'Transfer(list([{ from_ : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address, txs : list([ { to_ : "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" as address, token_id : (0 as nat), amount : (10000000000 as nat) } ]) as list }]))' --output-file ./test/fa2Parameter.tz --protocol nairobi +``` -tezos-client originate contract fa2uUSDKathmandunet transferring 0 from alice running ./test/fa2.tz --init "$(cat ./test/fa2_uUSD_storage.tz)" --burn-cap 1 --force +octez-client originate contract fa2uUSDNairobinet transferring 0 from alice running ./test/fa2.tz --init "$(cat ./test/fa2_uUSD_storage.tz)" --burn-cap 1 --force -tezos-client transfer 0 from myFirstKey to fa2uUSDKathmandunet --arg "$(cat ./test/fa2Parameter.tz)" --burn-cap 1 +octez-client transfer 0 from myFirstKey to fa2uUSDNairobinet --arg "$(cat ./test/fa2Parameter.tz)" --burn-cap 1 ## EURL -ligo compile contract ./test/fa2.jsligo --entry-point main --output-file ./test/fa2.tz --protocol kathmandu +ligo compile contract ./test/fa2.jsligo --output-file ./test/fa2.tz --protocol nairobi -ligo compile storage ./test/fa2.jsligo "$(cat ./test/fa2_EURL_storage.jsligo)" --entry-point main --output-file ./test/fa2_EURL_storage.tz --protocol kathmandu +ligo compile storage ./test/fa2.jsligo "$(cat ./test/fa2_EURL_storage.jsligo)" --output-file ./test/fa2_EURL_storage.tz --protocol nairobi -ligo compile parameter ./test/fa2.jsligo 'Transfer(list([{ from_ : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address, tx : list([ { to_ : "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" as address, token_id : 0 as nat, quantity : 10000000000 as nat } ]) as list }]))' --output-file ./test/fa2Parameter.tz --protocol kathmandu - -tezos-client originate contract fa2EURLKathmandunet transferring 0 from alice running ./test/fa2.tz --init "$(cat ./test/fa2_EURL_storage.tz)" --burn-cap 1 --force +``` +ligo compile parameter ./test/fa2.jsligo 'Transfer(list([{ from_ : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address, txs : list([ { to_ : "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" as address, token_id : (0 as nat), amount : (10000000000 as nat) } ]) as list }]))' --output-file ./test/fa2Parameter.tz --protocol nairobi +``` +octez-client originate contract fa2EURLNairobinet transferring 0 from alice running ./test/fa2.tz --init "$(cat ./test/fa2_EURL_storage.tz)" --burn-cap 1 --force -tezos-client transfer 0 from myFirstKey to fa2EURLKathmandunet --arg "$(cat ./test/fa2Parameter.tz)" --burn-cap 1 +octez-client transfer 0 from myFirstKey to fa2EURLNairobinet --arg "$(cat ./test/fa2Parameter.tz)" --burn-cap 1 -# Mocked rollup Contract +## USDt +ligo compile contract ./test/fa2.jsligo --output-file ./test/fa2.tz --protocol nairobi -## compile +ligo compile storage ./test/fa2.jsligo "$(cat ./test/fa2_USDt_storage.jsligo)" --output-file ./test/fa2_USDt_storage.tz --protocol nairobi ``` -ligo compile contract ./test/mock_deku_rollup.jsligo --output-file ./test/mock_deku_rollup.tz --protocol kathmandu +ligo compile parameter ./test/fa2.jsligo 'Transfer(list([{ from_ : "tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address, txs : list([ { to_ : "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb" as address, token_id : (0 as nat), amount : (10000000000 as nat) } ]) as list }]))' --output-file ./test/fa2Parameter.tz --protocol nairobi ``` +octez-client originate contract fa2USDtNairobinet transferring 0 from alice running ./test/fa2.tz --init "$(cat ./test/fa2_USDt_storage.tz)" --burn-cap 1 --force + +octez-client transfer 0 from myFirstKey to fa2USDtNairobinet --arg "$(cat ./test/fa2Parameter.tz)" --burn-cap 1 +# Mocked rollup Contract + +## compile + +``` +ligo compile contract ./test/mock_deku_rollup.jsligo --output-file ./test/mock_deku_rollup.tz --protocol nairobi +``` ## deploy @@ -104,11 +118,12 @@ tezos-client originate contract mock_rollup transferring 0 from myFirstKey runni Originate ```bash -tezos-client originate tx rollup from myFirstKey --burn-cap 100 +tezos-client originate tx rollup from myFirstKey --burn-cap 100 ``` ->BMLz4JnaDS7yUNtF51EWrspUEKAzWsikcrkbpTtmuJ8rzQcQdQt ->tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk ->txr1Q4iYZti8wfKXJi9CyagSnAHCogzX877kD + +> BMLz4JnaDS7yUNtF51EWrspUEKAzWsikcrkbpTtmuJ8rzQcQdQt +> tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk +> txr1Q4iYZti8wfKXJi9CyagSnAHCogzX877kD Submit operations @@ -137,4 +152,4 @@ sed s/FA12_CTEZ/${FA12_CTEZ_ADDRESS}/ < ./test/cfmm_initial_storage.mligo | sed ligo compile storage ./test/cfmm_tez_ctez.mligo "$(<./test/cfmm_storage.mligo)" --output-file ./test/cfmm_storage.tz tezos-client originate contract cfmm transferring 0.000001 from myFirstKey running 'file:./test/cfmm.tz' --init "$(<./test/cfmm_storage.tz)" --burn-cap 10 --force CFMM_ADDRESS=`tezos-client show known contract cfmm` -``` \ No newline at end of file +``` diff --git a/contract/src/contract.jsligo b/contract/src/contract.jsligo index 871286b..ec3ae8e 100644 --- a/contract/src/contract.jsligo +++ b/contract/src/contract.jsligo @@ -1,68 +1,49 @@ -// DEFINITIONS -type faTransferContractParameters = [address,[address,nat]]; //from,to,qty + +type faTransferContractParameters = [address, [address, nat]]; + type faTransferContract = contract; -type rollupContractParametersTORU = [ticket,tx_rollup_l2_address]; -type rollupContractParametersDEKU = [key_hash , ticket]; -type rollupContractParametersCHUSAI = ticket; +type rollupContractParametersDEKU = [key_hash, ticket]; -export type ticketType = -// @layout:comb -| ["XTZ"] -| ["FA", address] +export type ticketType = ["XTZ"] | ["FA", address]; -export type l2Type = -| [ "L2_DEKU" , key_hash] -| [ "L2_TORU" , tx_rollup_l2_address] -| [ "L2_CHUSAI"] -; +export type l2Type = | ["L2_DEKU", key_hash]; -export type faOp = -// @layout:comb +export type faOp = +// @layout comb { amountToTransfer: nat, //in mutez rollupAddress: address, - l2Type: l2Type, + l2Type, faAddress: address }; -export type xtzOp = -// @layout:comb -{ - amountToTransfer: nat, //in mutez - rollupAddress: address, - l2Type: l2Type -}; +export type xtzOp = +// @layout comb +{ amountToTransfer: nat, rollupAddress: address, l2Type }; -export type faPendingParameter = [address,faOp]; +export type faPendingParameter = [address, faOp]; -export type depositOp = -// @layout:comb -| ["FA_OP", faOp] -| ["XTZ_OP" , xtzOp] +export type depositOp = ["FA_OP", faOp] | ["XTZ_OP", xtzOp]; export type parameter = -// @layout:comb - | ["Deposit" , depositOp] - | ["PendingDeposit",faPendingParameter] - | ["WithdrawTORU" , ticket] //FIXME - | ["WithdrawDEKU" , ticket] - | ["WithdrawPendingDEKU", faPendingParameter] -; + | ["Deposit", depositOp] + | ["PendingDeposit", faPendingParameter] + | ["WithdrawDEKU", ticket] + | ["WithdrawPendingDEKU", faPendingParameter]; -export type faPendingMapType = map<[address,bytes],faOp>; +export type faPendingMapType = map<[address, bytes], faOp>; export type storage = { - treasuryAddress : address, //treasury address who will hold the collateral. We do this because an originated contract cannot be the initiator of transactions with fa1.2 contracts, an implicit account has to do transactions directly. - faPendingDeposits : faPendingMapType, //map of future tickets to deposit on behalf of implicit account destination - faPendingWithdrawals : faPendingMapType, //map of tickets to redeem back to implicit account destination + treasuryAddress: address, //treasury address who will hold the collateral. We do this because an originated contract cannot be the initiator of transactions with fa1.2 contracts, an implicit account has to do transactions directly. + faPendingDeposits: faPendingMapType, //map of future tickets to deposit on behalf of implicit account destination + faPendingWithdrawals: faPendingMapType }; +export type return_ = [list, storage]; -export type return_ = [list, storage]; - -type read_ticket_return = [[address, [bytes , nat]] , ticket]; +type read_ticket_return = [[address, [bytes, nat]], ticket]; /** ERROR MAP FOR UI DISPLAY or TESTS let errorMap : map = Map.literal(list([ @@ -75,157 +56,263 @@ type read_ticket_return = [[address, [bytes , nat]] , ticket]; ["7","The entrypoint contract *transfer* does not exist or is not a valid fa1.2 contract"], ["8","The entrypoint contract *approve* does not exist or is not a valid fa1.2 contract"], ["9","only the treasury can call directly this endpoint"], - ["10", "Invalid rollup address for TORU !"], ["11", "Invalid rollup address for DEKU !"], ["12", "Cannot find a Fa12PendingDeposit for the current inputs on contract storage"], - ["13", "Invalid rollup address for CHUSAI !"], - ["14", "CHUSAI is not ready for FA1.2"], ])); */ - // FUNCTIONS -const getFATransferContract = (faContractAddr: address) : faTransferContract => { - let transferOption: option = Tezos.get_entrypoint_opt("%transfer", faContractAddr); - let transfer = match (transferOption ,{ - Some : (contract : faTransferContract) => contract, - None : () => failwith("7") - }); - return transfer; +const getFATransferContract = (faContractAddr: address): faTransferContract => { + let transferOption: option = + Tezos.get_entrypoint_opt("%transfer", faContractAddr); + let transfer = + match( + transferOption, + { + Some: (contract: faTransferContract) => contract, + None: () => failwith("7") + } + ); + return transfer }; -const getRollupDEKUContract = (a : address) : contract => { - let contractOption: option> = Tezos.get_entrypoint_opt("%deposit", a); - let c = match (contractOption ,{ - Some : (c : contract) => c, - None : () => failwith("11") - }); - return c; -} - -const getRollupTORUContract = (a : address) : contract => { - let contractOption: option> = Tezos.get_entrypoint_opt("%deposit", a); - let c = match (contractOption ,{ - Some : (c : contract) => c, - None : () => failwith("10") - }); - return c; -} - -const deposit = ([op,store]: [depositOp,storage]): return_ => { - - return match( op , { - FA_OP : (faOp : faOp) => { - if(faOp.amountToTransfer < (1 as nat)) return failwith("0"); - - const b = Bytes.pack(FA(faOp.faAddress)); - return [list([]), {...store,faPendingDeposits : Map.add([Tezos.get_source(),b], faOp ,store.faPendingDeposits)}]; //we just keep this on storage and wait for the treasury user to continue the flow - }, - - XTZ_OP : (xtzOp : xtzOp) => { - if(xtzOp.amountToTransfer < (1 as nat)) return failwith("0"); - if(Tezos.get_amount() < (xtzOp.amountToTransfer * (1 as mutez))) return failwith("3"); - - //create XTZ ticket - let tic: ticket = Tezos.create_ticket(Bytes.pack(XTZ()),xtzOp.amountToTransfer); - - //send ticket to rollup - let op : operation = match(xtzOp.l2Type , { - L2_DEKU : (kh : key_hash) => Tezos.transaction([kh, tic],0 as mutez,getRollupDEKUContract(xtzOp.rollupAddress)), - L2_TORU : (a : tx_rollup_l2_address) => Tezos.transaction([tic, a],0 as mutez,getRollupTORUContract(xtzOp.rollupAddress)), - L2_CHUSAI : () => Tezos.transaction(tic,0 as mutez,Tezos.get_contract_with_error(xtzOp.rollupAddress,"14") as contract) - }); - - return [list([op]),store]; - } - }); +const getRollupDEKUContract = (a: address) + : contract => { + let contractOption: option> = + Tezos.get_entrypoint_opt("%deposit", a); + let c = + match( + contractOption, + { + Some: (c: contract) => c, + None: () => failwith("11") + } + ); + return c }; -const faPendingDeposit = ([faPendingDepositParameter,store]:[faPendingParameter,storage]) : return_ => { - - //only the treasury can call directly this endpoint - if(Tezos.get_sender() != store.treasuryAddress) return failwith("9"); - - let b = Bytes.pack(FA(faPendingDepositParameter[1].faAddress)) ; - - let [faOpOpt, newFaPendingDeposits] : [option, faPendingMapType] = - Map.get_and_update([faPendingDepositParameter[0], b], (None() as option), store.faPendingDeposits); - - return match(faOpOpt,{ - None : () => failwith("12"), - Some : (faOp : faOp) => - //send ticket to rollup - match(faOp.l2Type , { - L2_DEKU : (a : address) => [list([Tezos.transaction([a, Tezos.create_ticket(b,faOp.amountToTransfer)],0 as mutez,getRollupDEKUContract(faOp.rollupAddress))]), {...store,faPendingDeposits : newFaPendingDeposits} ], //remove it from storage now - L2_TORU : (a : tx_rollup_l2_address) => [list([Tezos.transaction([Tezos.create_ticket(b,faOp.amountToTransfer), a],0 as mutez,getRollupTORUContract(faOp.rollupAddress))]), {...store,faPendingDeposits : newFaPendingDeposits} ], //remove it from storage now - L2_CHUSAI : () => failwith("14") - }) - }); +const deposit = ([op, store]: [depositOp, storage]): return_ => { + return match( + op, + { + FA_OP: (faOp: faOp) => { + if (faOp.amountToTransfer < (1 as nat)) return failwith("0"); + const b = Bytes.pack(FA(faOp.faAddress)); + return [ + list([]), + { + ...store, + faPendingDeposits: Map.add( + [Tezos.get_source(), b], + faOp, + store.faPendingDeposits + ) + } + ] + }, + XTZ_OP: (xtzOp: xtzOp) => { + if (xtzOp.amountToTransfer < (1 as nat)) return failwith("0"); + if (Tezos.get_amount() < (xtzOp.amountToTransfer * (1 as mutez))) return failwith( + "3" + ); + //create XTZ ticket + + let tic: ticket = + Option.unopt( + Tezos.create_ticket(Bytes.pack(XTZ()), xtzOp.amountToTransfer) + ); + //send ticket to rollup + + let op: operation = + match( + xtzOp.l2Type, + { + L2_DEKU: (kh: key_hash) => + Tezos.transaction( + [kh, tic], + 0 as mutez, + getRollupDEKUContract(xtzOp.rollupAddress) + ) + } + ); + return [list([op]), store] + } + } + ) }; -const withdrawDEKU = ([ticket,store]:[ticket,storage]) : return_ => { - - // Read/burn the ticket - let [[ticketerAddress, [typeBytes, qty]], _] : read_ticket_return = Tezos.read_ticket(ticket); - - // check if we are the ticketer - if(ticketerAddress != Tezos.get_self_address()) return failwith("4"); - - let typeOpt: option = Bytes.unpack(typeBytes); - return match (typeOpt ,{ - Some : (ticketType : ticketType) => { - // try with XTZ first - match(ticketType , { - XTZ : () => { - let destinationContract : contract = Tezos.get_contract_with_error(Tezos.get_source(),"5"); - //give back the XTZ to the destination - return [list([Tezos.transaction(unit,qty * (1 as mutez),destinationContract)]),store]; - }, - FA : (faAddress : address) => - //look if already have something to aggregate. For l2Type: L2_DEKU( Crypto.hash_key("edpktz4xg6csJnJ5vcmMb2H37sWXyBDcoAp3XrBvjRaTSQ1zmZTeRQ" as key)), we use whatever dummy value because this field is no more needed and we cannot get the information anyway - match( Map.find_opt([Tezos.get_source(),typeBytes],store.faPendingWithdrawals), { - None : () => [list([]), {...store,faPendingWithdrawals : Map.add([Tezos.get_source(),typeBytes],{ - amountToTransfer: qty, //in mutez - rollupAddress: Tezos.get_sender(), - l2Type: L2_DEKU( Crypto.hash_key("edpktz4xg6csJnJ5vcmMb2H37sWXyBDcoAp3XrBvjRaTSQ1zmZTeRQ" as key)), - faAddress: faAddress - } ,store.faPendingWithdrawals)}], - Some : (existing : fa12Op) => [list([]), {...store,faPendingWithdrawals : Map.add([Tezos.get_source(),typeBytes],{...existing, - amountToTransfer: qty + existing.amountToTransfer - },store.faPendingWithdrawals)}] - }), - }); - }, - None : () => failwith("6") - }); - - }; - -const withdrawPendingDEKU = ([faPendingDepositParameter,store]:[faPendingParameter,storage]) : return_ => { - +const faPendingDeposit = ( + [faPendingDepositParameter, store]: [faPendingParameter, storage] +): return_ => { //only the treasury can call directly this endpoint - if(Tezos.get_sender() != store.treasuryAddress) return failwith("9"); - let b = Bytes.pack(FA(faPendingDepositParameter[1].faAddress)) ; + if (Tezos.get_sender() != store.treasuryAddress) return failwith("9"); + let b = Bytes.pack(FA(faPendingDepositParameter[1].faAddress)); + let [faOpOpt, newFaPendingDeposits]: [option, faPendingMapType] = + Map.get_and_update( + [faPendingDepositParameter[0], b], + (None() as option), + store.faPendingDeposits + ); + return match( + faOpOpt, + { + None: () => failwith("12"), + Some: (faOp: faOp) => + //send ticket to rollup + + match( + faOp.l2Type, + { + L2_DEKU: (a: key_hash) => + [ + list( + [ + Tezos.transaction( + [ + a, + Option.unopt( + Tezos.create_ticket(b, faOp.amountToTransfer) + ) + ], + 0 as mutez, + getRollupDEKUContract(faOp.rollupAddress) + ) + ] + ), + { ...store, faPendingDeposits: newFaPendingDeposits } + ] //remove it from storage now + } + ) + } + ) +}; + +const withdrawDEKU = (ticket: ticket, store: storage): return_ => { + // Read/burn the ticket + + let [[ticketerAddress, [typeBytes, qty]], _]: read_ticket_return = + Tezos.read_ticket(ticket); + // check if we are the ticketer + + if (ticketerAddress != Tezos.get_self_address()) return failwith("4"); + let typeOpt: option = Bytes.unpack(typeBytes); + return match( + typeOpt, + { + Some: (ticketType: ticketType) => { + // try with XTZ first + + match( + ticketType, + { + XTZ: () => { + let destinationContract: contract = + Tezos.get_contract_with_error(Tezos.get_source(), "5"); + //give back the XTZ to the destination + + return [ + list( + [ + Tezos.transaction( + unit, + qty * (1 as mutez), + destinationContract + ) + ] + ), + store + ] + }, + FA: (faAddress: address) => + //look if already have something to aggregate. For l2Type: L2_DEKU( Crypto.hash_key("edpktz4xg6csJnJ5vcmMb2H37sWXyBDcoAp3XrBvjRaTSQ1zmZTeRQ" as key)), we use whatever dummy value because this field is no more needed and we cannot get the information anyway + + match( + Map.find_opt( + [Tezos.get_source(), typeBytes], + store.faPendingWithdrawals + ), + { + None: () => + [ + list([]), + { + ...store, + faPendingWithdrawals: Map.add( + [Tezos.get_source(), typeBytes], + { + amountToTransfer: qty, //in mutez + rollupAddress: Tezos.get_sender(), + l2Type: L2_DEKU( + Crypto.hash_key( + "edpktz4xg6csJnJ5vcmMb2H37sWXyBDcoAp3XrBvjRaTSQ1zmZTeRQ" as + key + ) + ), + faAddress: faAddress + }, + store.faPendingWithdrawals + ) + } + ], + Some: (existing: faOp) => + [ + list([]), + { + ...store, + faPendingWithdrawals: Map.add( + [Tezos.get_source(), typeBytes], + { + ...existing, + amountToTransfer: qty + existing.amountToTransfer + }, + store.faPendingWithdrawals + ) + } + ] + } + ) + } + ) + }, + None: () => failwith("6") + } + ) +}; +const withdrawPendingDEKU = ( + [faPendingDepositParameter, store]: [faPendingParameter, storage] +): return_ => { + //only the treasury can call directly this endpoint + + if (Tezos.get_sender() != store.treasuryAddress) return failwith("9"); + let b = Bytes.pack(FA(faPendingDepositParameter[1].faAddress)); //check pending withdraw found or not - let [_faOpOpt, newFaPendingWithdrawals] : [option, faPendingMapType] = - Map.get_and_update([faPendingDepositParameter[0], b], (None() as option), store.faPendingWithdrawals); - return [list([]),{...store,faPendingWithdrawals : newFaPendingWithdrawals} ]; - //send back FA1.2 token ownership to the destination, leave found item out of list and let treasury to do final token fa1.2 transaction - + let [_faOpOpt, newFaPendingWithdrawals]: [option, faPendingMapType] = + Map.get_and_update( + [faPendingDepositParameter[0], b], + (None() as option), + store.faPendingWithdrawals + ); + return [list([]), { ...store, faPendingWithdrawals: newFaPendingWithdrawals }] +//send back FA1.2 token ownership to the destination, leave found item out of list and let treasury to do final token fa1.2 transaction + }; // MAIN -export const main = (params:[parameter , storage]): return_ => { - let [action , store] = params; - return match (action, { - Deposit : (op : depositOp) => deposit([op,store]), - PendingDeposit : (faPendingDepositParameter:faPendingParameter) => faPendingDeposit([faPendingDepositParameter,store]) , - WithdrawDEKU : (ticket : ticket) => withdrawDEKU(ticket,store), - WithdrawPendingDEKU : (faPendingDepositParameter:faPendingParameter) => withdrawPendingDEKU([faPendingDepositParameter,store]), - WithdrawTORU : (_ticket : ticket) => [list([]),store] //FIXME to finish one day - }) +export const main = (params: [parameter, storage]): return_ => { + let [action, store] = params; + return match( + action, + { + Deposit: (op: depositOp) => deposit([op, store]), + PendingDeposit: (faPendingDepositParameter: faPendingParameter) => + faPendingDeposit([faPendingDepositParameter, store]), + WithdrawDEKU: (t: ticket) => withdrawDEKU(t, store), + WithdrawPendingDEKU: (faPendingDepositParameter: faPendingParameter) => + withdrawPendingDEKU([faPendingDepositParameter, store]) + } + ) }; diff --git a/contract/test/.ligo/repository_id b/contract/test/.ligo/repository_id new file mode 100644 index 0000000..8db4b95 --- /dev/null +++ b/contract/test/.ligo/repository_id @@ -0,0 +1 @@ +5a44492a-696e-4d71-4dde-0ff5f3edf18b \ No newline at end of file diff --git a/contract/test/fa12.jsligo b/contract/test/fa12.jsligo index 170e6ad..fed5a0e 100644 --- a/contract/test/fa12.jsligo +++ b/contract/test/fa12.jsligo @@ -1,135 +1,124 @@ -type tokens = big_map; -type allowances = big_map<[address,address],nat>; // (sender,account) -> value +type tokens = big_map; -export type storage = -// @layout:comb -{ - tokens : tokens, - allowances : allowances, - total_amount : nat -}; +type allowances = big_map<[address, address], nat>; -export type transfer = -// @layout:comb -{ /* @annot:from */ from : address, - /* @annot:to */ to_ : address, - value : nat }; +export type storage = // @layout comb { tokens, allowances, total_amount: nat }; -export type approve = -// @layout:comb -{ - spender : address, - value : nat -}; +export type transfer = +// @layout comb +{ // @annot from from_: address, // @annot to to_: address, value: nat }; -type getAllowance = -// @layout:comb -{ - owner : address, - spender : address, - callback : contract -}; +export type approve = // @layout comb { spender: address, value: nat }; -type getBalance = -// @layout:comb -{ - owner : address, - callback : contract -}; +type getAllowance = +// @layout comb +{ owner: address, spender: address, callback: contract }; -type getTotalSupply = -// @layout:comb -{ - callback : contract -}; - -export type action = -// @layout:comb -| ["TransferFA12" , transfer] -| ["Approve" , approve] -| ["GetAllowance" , getAllowance] -| ["GetBalance" , getBalance] -| ["GetTotalSupply" , getTotalSupply]; +type getBalance = // @layout comb { owner: address, callback: contract }; +type getTotalSupply = // @layout comb { callback: contract }; -let getAllowances = ([p,s] : [transfer,storage]) : allowances => { - if(Tezos.get_source() == p.from) return s.allowances; - - let authorized_value = match(Big_map.find_opt([Tezos.get_source(),p.from],s.allowances) , { - Some : (value : nat) => value, - None : () => 0 as nat - }); - +export type action = + // @layout comb + | ["TransferFA12", transfer] + | ["Approve", approve] + | ["GetAllowance", getAllowance] + | ["GetBalance", getBalance] + | ["GetTotalSupply", getTotalSupply]; + +const getAllowances = ([p, s]: [transfer, storage]): allowances => { + if (Tezos.get_source() == p.from_) return s.allowances; + let authorized_value = + match( + Big_map.find_opt([Tezos.get_source(), p.from_], s.allowances), + { Some: (value: nat) => value, None: () => 0 as nat } + ); if (authorized_value < p.value) return failwith("Not Enough Allowance"); - - return Big_map.update([Tezos.get_source(),p.from],Some(abs(authorized_value - p.value)),s.allowances); + return Big_map.update( + [Tezos.get_source(), p.from_], + Some(abs(authorized_value - p.value)), + s.allowances + ) }; -let transfer = ([p,s] : [transfer,storage]) : [list , storage] => { - let new_allowances = getAllowances([p,s]) ; - let sender_balance = match(Big_map.find_opt(p.from,s.tokens) , { - Some : (value : nat) => value, - None : () => 0 as nat - }); - +const transfer = ([p, s]: [transfer, storage]): [list, storage] => { + let new_allowances = getAllowances([p, s]); + let sender_balance = + match( + Big_map.find_opt(p.from_, s.tokens), + { Some: (value: nat) => value, None: () => 0 as nat } + ); if (sender_balance < p.value) return failwith("Not Enough Balance"); + let new_tokens_map = + Big_map.update(p.from_, Some(abs(sender_balance - p.value)), s.tokens); + let receiver_balance = + match( + Big_map.find_opt(p.to_, s.tokens), + { Some: (value: nat) => value, None: () => 0 as nat } + ); + let new_new_tokens_map = + Big_map.update(p.to_, Some(receiver_balance + p.value), new_tokens_map); + return [ + list([]) as list, + { ...s, tokens: new_new_tokens_map, allowances: new_allowances } + ] +}; - let new_tokens_map = Big_map.update(p.from,Some(abs(sender_balance - p.value)),s.tokens); - let receiver_balance = match(Big_map.find_opt(p.to_,s.tokens), { - Some : (value : nat) => value, - None : () => 0 as nat - }); - let new_new_tokens_map = Big_map.update(p.to_,Some(receiver_balance + p.value),new_tokens_map); - - return [ list([]) as list , {...s , tokens : new_new_tokens_map, allowances : new_allowances}]; - }; - - -let approve = ([p,s] : [approve , storage]) : [list , storage] => { - let previous_value = match(Big_map.find_opt([p.spender, Tezos.get_source()],s.allowances) , { - Some : (value : nat) => value, - None : () => 0 as nat - }); - - if(previous_value > (0 as nat) && p.value > (0 as nat)) return failwith("Unsafe Allowance Change"); - - let new_allowances = Big_map.update([p.spender, Tezos.get_source()],Some(p.value),s.allowances); - - return [ list([]) as list , {...s , allowances : new_allowances}]; -}; - -let getAllowance = ([p,s] : [getAllowance , storage]) : [list , storage] => { - let value = match(Big_map.find_opt([p.owner, p.spender],s.allowances) , { - Some : (value : nat) => value, - None : () => 0 as nat - }); +const approve = ([p, s]: [approve, storage]): [list, storage] => { + let previous_value = + match( + Big_map.find_opt([p.spender, Tezos.get_source()], s.allowances), + { Some: (value: nat) => value, None: () => 0 as nat } + ); + if (previous_value > (0 as nat) && p.value > (0 as nat)) return failwith( + "Unsafe Allowance Change" + ); + let new_allowances = + Big_map.update( + [p.spender, Tezos.get_source()], + Some(p.value), + s.allowances + ); + return [list([]) as list, { ...s, allowances: new_allowances }] +}; +const getAllowance = ([p, s]: [getAllowance, storage]) + : [list, storage] => { + let value = + match( + Big_map.find_opt([p.owner, p.spender], s.allowances), + { Some: (value: nat) => value, None: () => 0 as nat } + ); let op = Tezos.transaction(value, 0 as mutez, p.callback); - - return [list([op]),s]; + return [list([op]), s] }; -let getBalance = ([p,s] : [getBalance , storage]) : [list , storage] => { - let value = match(Big_map.find_opt(p.owner,s.tokens), { - Some : (value : nat) => value, - None : () => 0 as nat - }); - let op = Tezos.transaction(value,0 as mutez, p.callback); - return [list([op]),s]; +const getBalance = ([p, s]: [getBalance, storage]): [list, storage] => { + let value = + match( + Big_map.find_opt(p.owner, s.tokens), + { Some: (value: nat) => value, None: () => 0 as nat } + ); + let op = Tezos.transaction(value, 0 as mutez, p.callback); + return [list([op]), s] }; -let getTotalSupply = ([p,s] : [getTotalSupply , storage]) : [list, storage] => { - let total = s.total_amount; - let op = Tezos.transaction(total, 0 as mutez, p.callback); - return [list([op]),s]; +const getTotalSupply = ([p, s]: [getTotalSupply, storage]) + : [list, storage] => { + let total = s.total_amount; + let op = Tezos.transaction(total, 0 as mutez, p.callback); + return [list([op]), s] }; -export let main = ([a,s]:[action , storage]) : [list, storage] => { - return match(a , { - TransferFA12 : (p : transfer) => transfer (p,s), - Approve : (p: transfer) => approve (p,s), - GetAllowance : (p: transfer) => getAllowance (p,s), - GetBalance : (p: transfer) => getBalance (p,s), - GetTotalSupply : (p: transfer) => getTotalSupply (p,s) -}); +export const main = ([a, s]: [action, storage]): [list, storage] => { + return match( + a, + { + TransferFA12: (p: transfer) => transfer([p, s]), + Approve: (p: approve) => approve([p, s]), + GetAllowance: (p: getAllowance) => getAllowance([p, s]), + GetBalance: (p: getBalance) => getBalance([p, s]), + GetTotalSupply: (p: getTotalSupply) => getTotalSupply([p, s]) + } + ) }; \ No newline at end of file diff --git a/contract/test/fa2.jsligo b/contract/test/fa2.jsligo index 3ff2abb..a746ba1 100644 --- a/contract/test/fa2.jsligo +++ b/contract/test/fa2.jsligo @@ -1,301 +1,412 @@ -// This file implement the TZIP-12 protocol (a.k.a FA2) for NFT on Tezos +// This file implement the TZIP-12 protocol (a.k.a FA2) for Multi asset on Tezos // copyright Wulfman Corporation 2021 - // Errors -namespace Errors { -export type t = string; - -export const undefined_token = "FA2_TOKEN_UNDEFINED"; -export const ins_balance = "FA2_INSUFFICIENT_BALANCE"; -export const no_transfer = "FA2_TX_DENIED"; -export const not_owner = "FA2_NOT_OWNER"; -export const not_operator = "FA2_NOT_OPERATOR"; -export const not_supported = "FA2_OPERATORS_UNSUPPORTED"; -export const rec_hook_fail = "FA2_RECEIVER_HOOK_FAILED"; -export const send_hook_fail = "FA2_SENDER_HOOK_FAILED"; -export const rec_hook_undef = "FA2_RECEIVER_HOOK_UNDEFINED"; -export const send_hook_under = "FA2_SENDER_HOOK_UNDEFINED"; - -export const only_sender_manage_operators = "The sender can only manage operators for his own token"; -}; + +// @no_mutation +const undefined_token = "FA2_TOKEN_UNDEFINED"; + +// @no_mutation +const ins_balance = "FA2_INSUFFICIENT_BALANCE"; + +// @no_mutation +const no_transfer = "FA2_TX_DENIED"; + +// @no_mutation +const not_owner = "FA2_NOT_OWNER"; + +// @no_mutation +const not_operator = "FA2_NOT_OPERATOR"; + +// @no_mutation +const not_supported = "FA2_OPERATORS_UNSUPPORTED"; + +// @no_mutation +const rec_hook_fail = "FA2_RECEIVER_HOOK_FAILED"; + +// @no_mutation +const send_hook_fail = "FA2_SENDER_HOOK_FAILED"; + +// @no_mutation +const rec_hook_undef = "FA2_RECEIVER_HOOK_UNDEFINED"; + +// @no_mutation +const send_hook_under = "FA2_SENDER_HOOK_UNDEFINED"; + +// @no_mutation +const wrong_amount = "WRONG_AMOUNT"; + +// @no_mutation +const only_sender_manage_operators = + "The sender can only manage operators for his own token"; + +// This file implement the TZIP-12 protocol (a.k.a FA2) for Multi asset on Tezos +// copyright Wulfman Corporation 2021 namespace Operators { - type owner = address; + type owner = address; type operator = address; type token_id = nat; export type t = big_map<[owner, operator], set>; - // if transfer policy is Owner_or_operator_transfer - export const assert_authorisation = ([operators, from_, token_id]: [t, address, nat]): unit => { - const sender_ = (Tezos.get_sender ()); - if (sender_ != from_){ - const authorized = match ((Big_map.find_opt ([from_,sender_], operators)), - {Some: (a : set) => a , None : () => Set.empty}); - if (!(Set.mem (token_id, authorized))) - {return failwith (Errors.not_operator)} + + export const assert_authorisation = ( + [operators, from_, token_id]: [t, address, nat] + ): unit => { + const sender_ = (Tezos.get_sender()); + if (sender_ != from_) { + const authorized = + match( + (Big_map.find_opt([from_, sender_], operators)), + { Some: (a: set) => a, None: () => Set.empty } + ); + if (!(Set.mem(token_id, authorized))) { + return failwith(not_operator) + } } }; -// if transfer policy is Owner_transfer -// export const assert_authorisation = ([operators, from_, token_id]: [t, address, nat]): unit => { -// const sender_ = Tezos.sender; -// if (sender_ != from_) -// {failwith (Errors.not_owner)} -// } - -// if transfer policy is No_transfer -// export const assert_authorisation = ([operators, from_, token_id]: [t, address, nat]): unit => -// failwith (Errors.no_owner) - - export const is_operator = ([operators, owner, operator, token_id] : [t , address , address , nat]) : bool => { - const authorized = match (Big_map.find_opt ([owner, operator], operators), - {Some: (a : set) => a , None : () => Set.empty}); - (Set.mem (token_id, authorized) || owner == operator) - }; - - const assert_update_permission = (owner : owner) : unit => - assert_with_error ((owner == (Tezos.get_sender ())), "The sender can only manage operators for his own token"); + // if transfer policy is Owner_transfer + // export const assert_authorisation = ([operators, from_, token_id]: [t, address, nat]): unit => { + // const sender_ = Tezos.sender; + // if (sender_ != from_) + // {failwith (not_owner)} + // } + // if transfer policy is No_transfer + // export const assert_authorisation = ([operators, from_, token_id]: [t, address, nat]): unit => + // failwith (no_owner) + + const assert_update_permission = (owner: owner): unit => + assert_with_error( + (owner == (Tezos.get_sender())), + "The sender can only manage operators for his own token" + ); // For an administator // const admin = tz1.... ; // assert_with_error ((Tezos.sender = admiin), "Only administrator can manage operators") - - export const add_operator = ([operators,owner,operator,token_id]: [t, owner, operator, token_id]) : t => { - if (owner == operator) { return operators; } // assert_authorisation always allow the owner so this case is not relevant - else { - assert_update_permission (owner); - let auth_tokens = match (Big_map.find_opt ([owner,operator], operators), - {Some : (ts: set) => ts , None : () => Set.empty}); - auth_tokens = Set.add (token_id, auth_tokens); - return Big_map.update ([owner,operator], Some (auth_tokens), operators); + export const add_operator = ( + [operators, owner, operator, token_id]: [t, owner, operator, token_id] + ): t => { + if (owner == operator) { + return operators + } else { + assert_update_permission(owner); + let auth_tokens = + match( + Big_map.find_opt([owner, operator], operators), + { Some: (ts: set) => ts, None: () => Set.empty } + ); + auth_tokens = Set.add(token_id, auth_tokens); + return Big_map.update([owner, operator], Some(auth_tokens), operators) } }; - - export const remove_operator = ([operators,owner,operator,token_id]: [t, owner, operator, token_id]) : t => { - if (owner == operator) { return operators; } // assert_authorisation always allow the owner so this case is not relevant - else { - assert_update_permission (owner); - const auth_tokens : option> = match (Big_map.find_opt ([owner,operator], operators), - {Some : (ts : set) => { - const ts = Set.remove (token_id, ts); - if (Set.cardinal (ts) == (0 as nat)) { return None ()} else { return Some (ts)}; - }, - None : () => None () - }); - return Big_map.update ([owner,operator], auth_tokens, operators); + export const remove_operator = ( + [operators, owner, operator, token_id]: [t, owner, operator, token_id] + ): t => { + if (owner == operator) { + return operators + } else { + assert_update_permission(owner); + const auth_tokens: option> = + match( + Big_map.find_opt([owner, operator], operators), + { + Some: (toks: set) => { + const ts = Set.remove(token_id, toks); + if (Set.cardinal(ts) == (0 as nat)) { + return None() + } else { + return Some(ts) + } + }, + None: () => None() + } + ); + return Big_map.update([owner, operator], auth_tokens, operators) } - }; + } }; namespace Ledger { type token_id = nat; type owner = address; - export type t = big_map<[owner,token_id],nat>; - - export const is_owner_of = ([ledger,token_id,owner]: [t, token_id, address]): bool => { - return match(Big_map.find_opt ([owner,token_id], ledger), { - None : () => {return false}, - Some : (quantity : nat) => {if(quantity == ( 0 as nat )){ return false;}else { return true;}} - } + type amount_ = nat; + export type t = big_map<[owner, token_id], amount_>; + const get_for_user = ([ledger, owner, token_id]: [t, owner, token_id]): nat => + match( + (Big_map.find_opt([owner, token_id], ledger)), + { Some: (a: amount_) => a, None: () => 0 as nat } ); + const set_for_user = ( + [ledger, owner, token_id, amount_]: [t, owner, token_id, amount_] + ): t => + Big_map.update([owner, token_id], Some(amount_), ledger); + const decrease_token_amount_for_user = ( + [ledger, from_, token_id, amount_]: [t, owner, token_id, amount_] + ): t => { + let balance_ = get_for_user([ledger, from_, token_id]); + assert_with_error((balance_ >= amount_), ins_balance); + balance_ = abs(balance_ - amount_); + return set_for_user([ledger, from_, token_id, balance_]) }; - - const assert_owner_of = ([ledger,token_id,owner]: [t, token_id, address]): unit => - assert_with_error (is_owner_of (ledger, token_id, owner), Errors.ins_balance); - - export const transfer_token_from_user_to_user = ([ledger,token_id,from_,to_,quantity]: [t, token_id, owner, owner,nat]): t => { - assert_owner_of (ledger, token_id, from_); - const current_quantity_from : nat = Option.unopt(Big_map.find_opt([from_,token_id],ledger)); - if(current_quantity_from < quantity) return failwith("Not enough balance"); - const ledgerFrom = Big_map.update ([from_,token_id], Some(abs(current_quantity_from - quantity)), ledger); - - return match(Big_map.find_opt([to_,token_id],ledgerFrom), { - None : () => { - return Big_map.update ([to_,token_id], Some (quantity), ledgerFrom) - }, - Some : (current_quantity_to : nat) => { - return Big_map.update ([to_,token_id], Some (quantity + current_quantity_to), ledgerFrom) - } - }); - - }; + const increase_token_amount_for_user = ( + [ledger, to_, token_id, amount_]: [t, owner, token_id, amount_] + ): t => { + let balance_ = get_for_user([ledger, to_, token_id]); + balance_ = balance_ + amount_; + return set_for_user([ledger, to_, token_id, balance_]) + } }; export namespace TokenMetadata { - // This should be initialized at origination, conforming to either + // This should be initialized at origination, conforming to either // TZIP-12 : https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-12/tzip-12.md#token-metadata - // or TZIP-16 : https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-12/tzip-12.md#contract-metadata-tzip-016 - export type data = {token_id:nat,token_info:map}; - export type t = big_map ; - - export const get_token_metadata = ([token_id, tm] : [nat, t]) : data => - match (Big_map.find_opt (token_id, tm), - {Some : (data : data) => data, - None : () => failwith (Errors.undefined_token)}); + // or TZIP-16 : https://gitlab.com/tezos/tzip/-/blob/master/proposals/tzip-12/tzip-12.md#contract-metadata-tzip-016 + + export type data = { token_id: nat, token_info: map }; + export type t = big_map; + const data1 = + Map.literal( + list( + [ + ["name", bytes `FA2 multi asset 1`], + ["symbol", bytes `FMA1`], + ["decimals", bytes `3`] + ] + ) + ); + const data3 = + Map.literal( + list( + [ + ["name", bytes `FA2 multi asset 3`], + ["symbol", bytes `FMA3`], + ["decimals", bytes `3`] + ] + ) + ); + export const init = (): t => + Big_map.literal( + list( + [ + [1 as nat, { token_id: 1 as nat, token_info: data1 }], + [3 as nat, { token_id: 3 as nat, token_info: data3 }] + ] + ) + ); + export const get_token_metadata = ([token_id, tm]: [nat, t]): data => + match( + Big_map.find_opt(token_id, tm), + { + Some: (data: data) => data, + None: () => failwith(undefined_token) + } + ) +}; + +type metadataType = big_map; + +const metadata = + bytes `{ + "name":"FA2", + "description":"Example FA2 implementation", + "version":"0.1.0", + "license":{"name":"MIT"}, + "authors":["Pierre-Emmanuel Wulfman"], + "homepage":"", + "source":{"tools":["Ligo"], "location":"https://github.com/ligolang/contract-catalogue/tree/main/lib/fa2"}, + "interfaces":["TZIP-012"], + "errors":[], + "views":[]}`; + +const init = (): metadataType => { + return Big_map.literal( + list([["", bytes `tezos-storage:data`], ["data", metadata]]) + ) }; namespace Storage { type token_id = nat; + type owner = address; export type t = { - ledger : Ledger.t, - token_metadata : TokenMetadata.t, - operators : Operators.t, - token_ids : list, + ledger: Ledger.t, + operators: Operators.t, + token_metadata: TokenMetadata.t, + metadata: metadataType, + owner_token_ids: set<[owner, token_id]>, + token_ids: set }; - - export const is_owner_of = ([s,owner,token_id]: [t, address, token_id]) : bool => - Ledger.is_owner_of (s.ledger, token_id, owner); - - export const assert_token_exist = ([s, token_id]: [t, nat]) : unit => { - const _ = Option.unopt_with_error (Big_map.find_opt (token_id, s.token_metadata), - Errors.undefined_token); - }; - - export const set_ledger = ([s, ledger]: [t, Ledger.t]) : t => ({...s, ledger : ledger}); - - export const get_operators = (s:t) : Operators.t => s.operators; - export const set_operators = ([s, operators]: [t, Operators.t]) : t => ({...s, operators : operators}); - - export const get_balance = ([s, owner, token_id] : [t, address, nat]) : nat => { - assert_token_exist (s, token_id); - if (is_owner_of (s, owner, token_id)) {return (1 as nat)} else {return (0 as nat)} + export const assert_token_exist = ([s, token_id]: [t, nat]): unit => { + const _ = + Option.unopt_with_error( + Big_map.find_opt(token_id, s.token_metadata), + undefined_token + ) }; + export const set_ledger = ([s, ledger]: [t, Ledger.t]): t => + ({ ...s, ledger: ledger }); + export const get_operators = (s: t): Operators.t => s.operators; + export const set_operators = ([s, operators]: [t, Operators.t]): t => + ({ ...s, operators: operators }) }; - export type storage = Storage.t; // Transfer entrypoint -export type atomic_trans = -// @layout:comb -{ - to_ : address, - token_id : nat, - quantity : nat -}; -export type transfer_from = { - from_ : address, - tx : list, -}; +export type atomic_trans = +// @layout comb +{ to_: address, token_id: nat, amount: nat }; + +type transfer_from = { from_: address, txs: list }; export type transfer = list; const transfer = ([t, s]: [transfer, storage]): [list, storage] => { - // This function process the "tx" list. Since all transfer share the same "from_" address, we use a se - const process_atomic_transfer = (from_ : address) - : (ledger: Ledger.t, t: atomic_trans) => Ledger.t => { - return (ledger: Ledger.t, t: atomic_trans) : Ledger.t => { - const {to_,token_id,quantity} = t; - Storage.assert_token_exist (s, token_id); - Operators.assert_authorisation (s.operators, from_, token_id); - const ledger = Ledger.transfer_token_from_user_to_user (ledger, token_id, from_, to_, quantity); - ledger - }; - }; - const process_single_transfer = ([ledger, t]: [Ledger.t, transfer_from]) : Ledger.t => { - const {from_,tx} = t; - const ledger = List.fold_left (process_atomic_transfer (from_), ledger, tx); - ledger + // This function process the "txs" list. Since all transfer share the same "from_" address, we use a se + + const process_atomic_transfer = (from_: address) + : (ledger: [Ledger.t, atomic_trans]) => Ledger.t => { + return ([l, t]: [Ledger.t, atomic_trans]): Ledger.t => { + const { to_, token_id, amount } = t; + Storage.assert_token_exist([s, token_id]); + Operators.assert_authorisation([s.operators, from_, token_id]); + let ledger = + Ledger.decrease_token_amount_for_user([l, from_, token_id, amount]); + ledger = + Ledger.increase_token_amount_for_user( + [ledger, to_, token_id, amount] + ); + return ledger + } + }; + const process_single_transfer = ([l, t]: [Ledger.t, transfer_from]): Ledger.t => { + const { from_, txs } = t; + const ledger = List.fold_left(process_atomic_transfer(from_), l, txs); + return ledger }; - const ledger = List.fold_left (process_single_transfer, s.ledger, t); - const s = Storage.set_ledger (s, ledger); - [list ([]),s] -} - -export type request = { - owner : address, - token_id : nat, + const ledger = List.fold_left(process_single_transfer, s.ledger, t); + //refresh set of owner,token_ids + + let store = + List.fold_left( + ([s, tf]: [storage, transfer_from]) => + List.fold_left( + ([s, at]: [storage, atomic_trans]) => + ( + { + ...s, + owner_token_ids: Set.add( + [at.to_, at.token_id], + s.owner_token_ids + ) + } + ), + s, + tf.txs + ), + s, + t + ); + store = Storage.set_ledger([s, ledger]); + return [list([]), store] }; +export type request = { owner: address, token_id: nat }; + type callback = -// @layout:comb -{ - request : request, - balance : nat, -}; +// @layout comb +{ request, balance: nat }; export type balance_of = -// @layout:comb -{ - requests : list, - callback : contract>, -}; +// @layout comb +{ requests: list, callback: contract> }; // Balance_of entrypoint -const balance_of = ([b, s] : [balance_of, storage]): [list, storage] => { - const {requests, callback} = b; - const get_balance_info = (request : request) : callback => { - const {owner,token_id} = request; - Storage.assert_token_exist (s, token_id); - let balance_ = 0 as nat; - if (Storage.is_owner_of (s, owner, token_id)) balance_ = 1 as nat; - ({request:request,balance:balance_}) + +const balance_of = ([b, s]: [balance_of, storage]): [list, storage] => { + const { requests, callback } = b; + const get_balance_info = (request: request): callback => { + const { owner, token_id } = request; + Storage.assert_token_exist([s, token_id]); + const balance_ = Ledger.get_for_user([s.ledger, owner, token_id]); + return ({ request: request, balance: balance_ }) }; - const callback_param = List.map (get_balance_info, requests); - const operation = Tezos.transaction (callback_param, (0 as tez), callback); - [list([operation]),s] + const callback_param = List.map(get_balance_info, requests); + const operation = Tezos.transaction(callback_param, (0 as tez), callback); + return [list([operation]), s] }; // Update_operators entrypoint -export type operator = -// @layout:comb -{ - owner : address, - operator : address, - token_id : nat, -}; -export type unit_update = ["Add_operator", operator] | ["Remove_operator", operator]; +export type operator = +// @layout comb +{ owner: address, operator: address, token_id: nat }; + +export type unit_update = + ["Add_operator", operator] | ["Remove_operator", operator]; + export type update_operators = list; -const update_ops = ([updates, s]: [update_operators, storage]): [list, storage] => { - const update_operator = ([operators,update] : [Operators.t, unit_update]) : Operators.t => match (update, - { Add_operator : (operator: operator) => Operators.add_operator (operators, operator.owner, operator.operator, operator.token_id) - , Remove_operator : (operator: operator) => Operators.remove_operator (operators, operator.owner, operator.operator, operator.token_id) - }); - let operators = Storage.get_operators (s); - operators = List.fold_left (update_operator, operators, updates); - const s = Storage.set_operators (s, operators); - [list([]),s] +const update_ops = ([updates, s]: [update_operators, storage]) + : [list, storage] => { + const update_operator = ([operators, update]: [Operators.t, unit_update]) + : Operators.t => + match( + update, + { + Add_operator: (operator: operator) => + Operators.add_operator( + [ + operators, + operator.owner, + operator.operator, + operator.token_id + ] + ), + Remove_operator: (operator: operator) => + Operators.remove_operator( + [ + operators, + operator.owner, + operator.operator, + operator.token_id + ] + ) + } + ); + let operators = Storage.get_operators(s); + operators = List.fold_left(update_operator, operators, updates); + const store = Storage.set_operators([s, operators]); + return [list([]), store] }; // If transfer_policy is No_transfer or Owner_transfer -//const update_ops : update_operators -> storage -> operation list * storage = -// fun (updates: update_operators) (s: storage) -> -// const () = failwith Errors.not_supported in +//const update_ops : update_operators -> storage -> operation list * storage = +// fun (updates: update_operators) (s: storage) -> +// const () = failwith not_supported in // ([]: operation list),s - export type parameter = -// @layout:comb -| ["Transfer", transfer] | ["Balance_of", balance_of] | ["Update_operators", update_operators] - -const main = ([p, s]: [parameter, storage]) : [list, storage] => match (p, -{ Transfer : (p : transfer ) => transfer (p, s) -, Balance_of : (p : balance_of ) => balance_of (p, s) -, Update_operators : (p : update_operator ) => update_ops (p, s) -}); + // @layout comb + | ["Transfer", transfer] + | ["Balance_of", balance_of] + | ["Update_operators", update_operators]; + +const main = (p: parameter, s: storage): [list, storage] => + match( + p, + { + Transfer: (p: transfer) => transfer([p, s]), + Balance_of: (p: balance_of) => balance_of([p, s]), + Update_operators: (p: update_operators) => update_ops([p, s]) + } + ); // @view -const get_balance = ([p, s] : [[address , nat] , storage]) : nat => { - const [owner, token_id] = p; - Storage.get_balance (s, owner, token_id); -}; - -// @view -const total_supply = ([token_id, s] : [nat , storage]) : nat => { - Storage.assert_token_exist (s, token_id); - (1 as nat) -}; +const all_owner_token_ids = (_: unit, s: storage): set<[address, nat]> => + s.owner_token_ids; // @view -const all_tokens = ([_, s] : [unit , storage]) : list => s.token_ids; - -// @view -const is_operator = ([op, s] : [operator , storage]) : bool => - Operators.is_operator (s.operators, op.owner, op.operator, op.token_id); +const all_token_ids = (_: unit, s: storage): set => s.token_ids; -// @view -const token_metadata = ([p, s] : [nat, storage]) : TokenMetadata.data => - TokenMetadata.get_token_metadata(p, s.token_metadata) diff --git a/contract/test/fa2_EURL_storage.jsligo b/contract/test/fa2_EURL_storage.jsligo index b143bf4..612ce0a 100644 --- a/contract/test/fa2_EURL_storage.jsligo +++ b/contract/test/fa2_EURL_storage.jsligo @@ -1,5 +1,4 @@ { - token_ids : list([0 as nat]) as list, operators : Big_map.empty as big_map<[address, address], set> , ledger : ( Big_map.literal( list([ [ ["tz1KkeNrP9YeL4NzU9ha5yuvxv8NYpWNd2LY" as address, 0 as nat] , (1000000000000000000 as nat)]]) @@ -8,10 +7,30 @@ [ (0 as nat) , {token_id : (0 as nat), token_info : Map.literal ( list([ - ["decimals", (0x36 as bytes)] , - ["name", (0x4c756768204575726f2070656767656420737461626c65636f696e as bytes) ], - ["symbol", (0x4555524c as bytes) ], - ["thumbnailUri", (0x697066733a2f2f516d63717359516e3870547851723350316459706759785161364751506d6f425453575138627075464575617165 as bytes)] + ["decimals", (bytes `6`)] , + ["name", (bytes `Lugh Euro pegged stablecoin`) ], + ["interfaces", (bytes `["TZIP-12"]`)], + ["description", (bytes `lorem ipsum`)], + ["symbol", (bytes `EURL`) ], + ["thumbnailUri", (bytes `ipfs://QmcqsYQn8pTxQr3P1dYpgYxQa6GQPmoBTSWQ8bpuFEuaqe`)] ])) - }] ]) ) as big_map}>) + }] ]) ) as big_map}>), + owner_token_ids: Set.empty as set<[address, nat]>, + token_ids: Set.empty as set, + metadata : Big_map.literal( + list([["", bytes `tezos-storage:data`], ["data", bytes `{ + "name":"FA2 TOKEN EURL", + "description":"Example of FA2 implementation", + "version":"0.0.1", + "license":{"name":"MIT"}, + "authors":["Marigold"], + "homepage":"https://marigold.dev", + "source":{ + "tools":["Ligo"], + "location":"https://github.com/ligolang/contract-catalogue/tree/main/lib/fa2"}, + "interfaces":["TZIP-012"], + "errors": [], + "views": [] + }`]]) + ) } \ No newline at end of file diff --git a/contract/test/fa2_USDt_storage.jsligo b/contract/test/fa2_USDt_storage.jsligo new file mode 100644 index 0000000..36e2910 --- /dev/null +++ b/contract/test/fa2_USDt_storage.jsligo @@ -0,0 +1,36 @@ +{ + operators : Big_map.empty as big_map<[address, address], set> , + ledger : ( Big_map.literal( list([ + [ ["tz1KkeNrP9YeL4NzU9ha5yuvxv8NYpWNd2LY" as address, 0 as nat] , (1000000000000000000000000 as nat)]]) + ) as big_map<[address,nat],nat> ), + token_metadata : ( Big_map.literal ( list([ + [ (0 as nat) , + {token_id : (0 as nat), + token_info : Map.literal ( list([ + ["decimals", (bytes `6`)] , + ["name", (bytes `Tether USD`) ], + ["interfaces", (bytes `["TZIP-12"]`)], + ["description", (bytes `lorem ipsum`)], + ["symbol", (bytes `USDt`) ], + ["thumbnailUri", (bytes `ipfs://QmRymVGWEudMfLrbjaEiXxngCRTDgWCsscjQMwizy4ZJjX`)] + ])) + }] ]) ) as big_map}>), + owner_token_ids: Set.empty as set<[address, nat]>, + token_ids: Set.empty as set, + metadata : Big_map.literal( + list([["", bytes `tezos-storage:data`], ["data", bytes `{ + "name":"FA2 TOKEN USDt", + "description":"Example of FA2 implementation", + "version":"0.0.1", + "license":{"name":"MIT"}, + "authors":["Marigold"], + "homepage":"https://marigold.dev", + "source":{ + "tools":["Ligo"], + "location":"https://github.com/ligolang/contract-catalogue/tree/main/lib/fa2"}, + "interfaces":["TZIP-012"], + "errors": [], + "views": [] + }`]]) + ) +} \ No newline at end of file diff --git a/contract/test/fa2_uUSD_storage.jsligo b/contract/test/fa2_uUSD_storage.jsligo index ad1507c..c716ae1 100644 --- a/contract/test/fa2_uUSD_storage.jsligo +++ b/contract/test/fa2_uUSD_storage.jsligo @@ -1,5 +1,4 @@ { - token_ids : list([0 as nat]) as list, operators : Big_map.empty as big_map<[address, address], set> , ledger : ( Big_map.literal( list([ [ ["tz1KkeNrP9YeL4NzU9ha5yuvxv8NYpWNd2LY" as address, 0 as nat] , (1000000000000000000000000 as nat)]]) @@ -8,10 +7,30 @@ [ (0 as nat) , {token_id : (0 as nat), token_info : Map.literal ( list([ - ["decimals", (0x3132 as bytes)] , - ["name", (0x796f757665732075555344 as bytes) ], - ["symbol", (0x75555344 as bytes) ], - ["thumbnailUri", (0x697066733a2f2f516d627668616e4e437879645a45624775315264716b47334c63704e4776375859734348677a5742586e6d785264 as bytes)] + ["decimals", (bytes `12`)] , + ["name", (bytes `youves uUSD`) ], + ["interfaces", (bytes `["TZIP-12"]`)], + ["description", (bytes `lorem ipsum`)], + ["symbol", (bytes `uUSD`) ], + ["thumbnailUri", (bytes `ipfs://QmbvhanNCxydZEbGu1RdqkG3LcpNGv7XYsCHgzWBXnmxRd`)] ])) - }] ]) ) as big_map}>) + }] ]) ) as big_map}>), + owner_token_ids: Set.empty as set<[address, nat]>, + token_ids: Set.empty as set, + metadata : Big_map.literal( + list([["", bytes `tezos-storage:data`], ["data", bytes `{ + "name":"FA2 TOKEN uUSD", + "description":"Example of FA2 implementation", + "version":"0.0.1", + "license":{"name":"MIT"}, + "authors":["Marigold"], + "homepage":"https://marigold.dev", + "source":{ + "tools":["Ligo"], + "location":"https://github.com/ligolang/contract-catalogue/tree/main/lib/fa2"}, + "interfaces":["TZIP-012"], + "errors": [], + "views": [] + }`]]) + ) } \ No newline at end of file diff --git a/contract/test/unit_contract.jsligo b/contract/test/unit_contract.jsligo index 162fde5..7f248cb 100644 --- a/contract/test/unit_contract.jsligo +++ b/contract/test/unit_contract.jsligo @@ -2,577 +2,1050 @@ #import "./mock_deku_rollup.jsligo" "ROLLUP" #import "./fa12.jsligo" "FA12" #import "./fa2.jsligo" "FA2" - -const errorMap : map = Map.literal(list([ - ["0", "Enter a positive and not null amount"], - ["2", "Invalid FA1.2 address!"], - ["3", "User needs to provide at least 'amountToTransfer' mutez"], - ["4", "We only accept tickets we created!"], - ["5", "Cannot find the destination implicit account contract"], - ["6", "The ticket does not contain a valid ticketType"], - ["7","The entrypoint contract *transfer* does not exist or is not a valid fa1.2 contract"], - ["8","The entrypoint contract *approve* does not exist or is not a valid fa1.2 contract"], - ["9","only the treasury can call directly this endpoint"], - ["10", "Invalid rollup address for TORU !"], - ["11", "Invalid rollup address for DEKU !"], - ["12", "Cannot find a Fa12PendingDeposit for the current inputs on contract storage"] -])); +const errorMap: map = + Map.literal( + list( + [ + ["0", "Enter a positive and not null amount"], + ["2", "Invalid FA1.2 address!"], + ["3", "User needs to provide at least 'amountToTransfer' mutez"], + ["4", "We only accept tickets we created!"], + ["5", "Cannot find the destination implicit account contract"], + ["6", "The ticket does not contain a valid ticketType"], + [ + "7", + "The entrypoint contract *transfer* does not exist or is not a valid fa1.2 contract" + ], + [ + "8", + "The entrypoint contract *approve* does not exist or is not a valid fa1.2 contract" + ], + ["9", "only the treasury can call directly this endpoint"], + ["10", "Invalid rollup address for TORU !"], + ["11", "Invalid rollup address for DEKU !"], + [ + "12", + "Cannot find a Fa12PendingDeposit for the current inputs on contract storage" + ] + ] + ) + ); //util function -let assert_failure = ([result,message] : [test_exec_result,string]) : bool => { - return match(result,{ - Success: (_ : nat) => false, - Fail: ( tee : test_exec_error ) => - match(tee,{ - Other: (msg : string) => {Test.log("ERROR Other : "+msg) ; return false}, - Balance_too_low : (_record : [ address , tez , tez ]) => {Test.log("ERROR Balance_too_low") ; return false}, - Rejected: (s:[michelson_program , address])=>{ Test.log (["expected error : ", message, " Actual : "]) ; Test.log(s[0]) ; return ((Test.eval(message)) == s[0]) } }) - }) - }; - - // reset state - let _ = Test.reset_state (4 as nat, list([]) as list ); - let treasury = Test.nth_bootstrap_account(0); - let sender1 : address = Test.nth_bootstrap_account(1); - let _ = Test.log("Sender 1 has balance : "); - let _ = Test.log(Test.get_balance(sender1)); - let _ = Test.log(sender1); - let sender2 : address = Test.nth_bootstrap_account(2); - let _ = Test.log("Sender 2 has balance : "); - let _ = Test.log(Test.get_balance(sender2)); - let _ = Test.log(sender2); - let sender3 : address = Test.nth_bootstrap_account(3); - let _ = Test.log("Sender 3 has balance : "); - let _ = Test.log(Test.get_balance(sender3)); - let _ = Test.log(sender3); - - - let _ = Test.set_baker(treasury); - let _ = Test.set_source(treasury); - - - //mock rollup origination - let [trollupaddr, rollupContrMichelson, _] = Test.originate(ROLLUP.main, Map.empty as map>, 0 as tez); - let rollupContr = Test.to_contract(trollupaddr); - let rollupAddress = Tezos.address(rollupContr); - let _ = Test.log("rollup contract deployed with values : "); - let _ = Test.log(rollupContr); - - //fa1.2 origination - let fabalance :nat = 4200 as nat; - let [tfaaddr, _, _] = Test.originate(FA12.main, //prepare allowance of 42 for later - {tokens : Big_map.literal(list([ [sender3,fabalance] ])) as big_map,allowances : Big_map.literal(list([ [[sender3,treasury],(42 as nat)] ])) as big_map<[address,address],nat>,total_amount : fabalance} - ,0 as tez); - let faContr = Test.to_contract(tfaaddr); - let faAddress = Tezos.address(faContr); - let _ = Test.log("fa contract deployed with values : "); - let _ = Test.log(faContr); - let _ = Test.log(Test.get_storage_of_address(faAddress)); - - //contract origination - - let contrStorage = { - treasuryAddress : treasury, - faPendingDeposits : Map.empty as CONTRACT.faPendingMapType, - faPendingWithdrawals : Map.empty as CONTRACT.faPendingMapType, - }; - let [taddr, _, _] = Test.originate(CONTRACT.main,contrStorage, 0 as tez); - let contr = Test.to_contract(taddr); - let contrAddress = Tezos.address(contr); - let _ = Test.log("contract deployed with values : "); - let _ = Test.log(contr); - - const xTZType : bytes = Bytes.pack(XTZ()); - const fAType : bytes = Bytes.pack(FA(faAddress)); - - // FUNCTIONS - - const _testDeposit = ([s,depositOp,xTZToCheck,fA12ToCheck] : [address,CONTRACT.depositOp,nat,nat]) : bool => { - Test.set_source(s); - - let faStorage : FA12.storage = Test.get_storage (tfaaddr); - - //check current value before testing - let oldSenderBalance = Test.get_balance(s); - let oldContractBalance = Test.get_balance(Tezos.address(contr)); - let oldTreasuryBalance = match(Big_map.find_opt(contrStorage.treasuryAddress,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - // not possible to do, so display it on log - //let oldTicketQty = Test.log(rollupStore); - Test.log("*** MANUAL CHECK : rollupStore before any test is launched ***"); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - Test.log(rollupStore); - - Test.log(depositOp); - let status = Test.transfer_to_contract(contr, Deposit(depositOp), xTZToCheck * (1 as mutez)); - Test.log(status); - - //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - - let _l2adr = match(depositOp , { - XTZ_OP : (xtzOp:xtzOp) => { - //check ticket on rollup - Test.log("*** MANUAL CHECK : rollupStore after test ***"); - Test.log(rollupStore); - Test.log (["*** MANUAL CHECK : expected additional ticket qty : ", xTZToCheck]) ; - Test.log (["*** MANUAL CHECK : actual ticket qty for inbox rollup : ","DO COMPARE MANUALLY"]) ; - //check contract balance. It should increase - assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance + (xTZToCheck * (1 as mutez))) ; - //check sender balance. It should decrease - assert(Test.get_balance(s) <= Option.unopt (oldSenderBalance - (xTZToCheck * (1 as mutez )))); - return xtzOp.l2Type}, - FA_OP : (faOp:faOp) => { - - - - //check FA12 tokens ownership - let contrStorage : CONTRACT.storage = Test.get_storage (taddr); - let treasuryBalance = match(Big_map.find_opt(contrStorage.treasuryAddress,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - let senderBalance = match(Big_map.find_opt(s,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - assert(treasuryBalance == oldTreasuryBalance); // transfer of token not yet done by the treasury - assert(senderBalance == fabalance); // transfer of token not yet done by the treasury - //check ticket on rollup - Test.log("*** MANUAL CHECK : rollupStore after test ***"); - Test.log(rollupStore); - Test.log (["*** MANUAL CHECK : expected additional ticket qty : ", fA12ToCheck]) ; - Test.log (["*** MANUAL CHECK : actual ticket qty for inbox rollup : ","DO COMPARE MANUALLY"]) ; - //check contract balance. It should not move - assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance) ; - return faOp.l2Type; +const assert_failure = ([result, message]: [test_exec_result, string]): bool => { + return match( + result, + { + Success: (_: nat) => false, + Fail: (tee: test_exec_error) => + match( + tee, + { + Other: (msg: string) => { + Test.log("ERROR Other : " + msg); + return false + }, + Balance_too_low: (_record: test_exec_error_balance_too_low) => { + Test.log("ERROR Balance_too_low"); + return false + }, + Rejected: (s: [michelson_program, address]) => { + Test.log(["expected error : ", message, " Actual : "]); + Test.log(s[0]); + return ((Test.eval(message)) == s[0]) + } + } + ) + } + ) +}; - } - }); - - return true; - }; +// reset state - const _testPendingDeposit = ([s,faPendingDeposit] : [address,CONTRACT.faPendingParameter]) : bool => { - Test.set_source(s); - - let faStorage : FA12.storage = Test.get_storage (tfaaddr); - - //check current value before testing - let oldContractBalance = Test.get_balance(Tezos.address(contr)); - let oldTreasuryBalance = match(Big_map.find_opt(contrStorage.treasuryAddress,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - - // not possible to do, so display it on log - //let oldTicketQty = Test.log(rollupStore); - Test.log("*** MANUAL CHECK : rollupStore before any test is launched ***"); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - Test.log(rollupStore); - - Test.log(faPendingDeposit); - let status = Test.transfer_to_contract(contr, PendingDeposit(faPendingDeposit), 0 as mutez); - Test.log(status); - //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - - //check FA1.2 tokens ownership - let faStorage : FA12.storage = Test.get_storage (tfaaddr); - let treasuryBalance = match(Big_map.find_opt(contrStorage.treasuryAddress,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - let _senderBalance = match(Big_map.find_opt(s,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - assert(oldTreasuryBalance == treasuryBalance ); //transfer should be done before this call - //check ticket on rollup - Test.log("*** MANUAL CHECK : rollupStore after test ***"); - Test.log(rollupStore); - Test.log (["*** MANUAL CHECK : actual ticket qty for inbox rollup : ","DO COMPARE MANUALLY"]) ; - //check contract balance. It should not move - assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance) ; - - return true; - }; - - const _testDepositFail = ( [s,depositOp,tezToPay,message] : [address,CONTRACT.depositOp,nat,string]) : bool => { - Test.set_source(s); - Test.log("Testing error to fail : "+ Option.unopt(Map.find_opt(message,errorMap))); - return assert_failure(Test.transfer_to_contract(contr, (Deposit(depositOp)), tezToPay * (1 as tez)),message); - }; +const _ = Test.reset_state(4 as nat, list([]) as list); - const _testPendingDepositFail = ( [s,faPendingDeposit,message] : [address,CONTRACT.faPendingParameter,string]) : bool => { - Test.set_source(s); - Test.log("Testing error to fail : "+ Option.unopt(Map.find_opt(message,errorMap))); - return assert_failure(Test.transfer_to_contract(contr, (PendingDeposit(faPendingDeposit)), 0 as tez),message); - }; +const treasury = Test.nth_bootstrap_account(0); - const _testWithdrawDEKU = ([s,withdrawParam,remainingBalanceToCheckOncontract,_remainingCtezQuantity] : [address,ROLLUP.withdrawParameter,tez,nat]) : bool => { - Test.set_source(s); - - let faStorage : FA12.storage = Test.get_storage (tfaaddr); - Test.log(faStorage); - - //check current value before testing - let oldTreasuryBalance = match(Big_map.find_opt(contrStorage.treasuryAddress,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - - //check current value before testing - let oldSenderBalance : tez = Test.get_balance(s); - Test.log("oldSenderBalance"); - Test.log(oldSenderBalance); - let oldContractBalance : tez = Test.get_balance(Tezos.address(contr)); - Test.log("oldContractBalance"); - Test.log(oldContractBalance); - - let oldSenderTokenBalance : nat = match(Big_map.find_opt(s,faStorage.tokens),{None:()=>(0 as nat),Some:(n:nat)=>n}); - Test.log("oldSenderTokenBalance"); - Test.log(oldSenderTokenBalance); - let oldContractTokenBalance : nat = match(Big_map.find_opt(contrAddress,faStorage.tokens),{None:()=>(0 as nat),Some:(n:nat)=>n}); - Test.log("oldContractTokenBalance"); - Test.log(oldContractTokenBalance); - - // not possible to do, so display it on log - //let oldTicketQty = Test.log(rollupStore); - Test.log("*** MANUAL CHECK : rollupStore before any test is launched ***"); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - Test.log(rollupStore); - - Test.log("withdrawParam"); - Test.log(withdrawParam); - let status = Test.transfer_to_contract(rollupContr, Withdraw(withdrawParam), 0 as tez); - Test.log(status); - //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - Test.log("*** MANUAL CHECK : rollupStore after any test is launched ***"); - Test.log(rollupStore); - //check balances for contract and user - - const ticketType : bytes = withdrawParam[1].data; - Test.log(ticketType); - const qty : nat = withdrawParam[1].amount; - Test.log(qty); - - if(ticketType == xTZType){ - //check contract balance. It should decrease - assert(Test.get_balance(Tezos.address(contr)) == remainingBalanceToCheckOncontract ); - assert(remainingBalanceToCheckOncontract == Option.unopt (oldContractBalance - (qty * (1 as mutez)))) ; - //check sender balance. It should increase - assert(Test.get_balance(s) <= (oldSenderBalance + (qty * (1 as tez )))); - return true; - } else if (ticketType == fAType) { - let newfastorage : FA12.storage = Test.get_storage(tfaaddr); - Test.log(newfastorage); - //check contract balance. It should equal to same value - assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance ); - //check sender token balance, it should be the same - assert(oldSenderTokenBalance == match(Big_map.find_opt(s,newfastorage.tokens),{None:()=>(0 as nat),Some:(n:nat)=>n})); - //check treasury token balance, it should be the same - assert(oldTreasuryBalance == match(Big_map.find_opt((Test.get_storage(taddr)).treasuryAddress,newfastorage.tokens),{None:()=>(0 as nat),Some:(n:nat)=>n})); - return true; - } else { - Test.log("Cannot find the correct ticketType"); - return false; - } - - }; +const sender1: address = Test.nth_bootstrap_account(1); +const _ = Test.log("Sender 1 has balance : "); - const _testWithdrawFail = ([s,withdrawParam] : [address,ROLLUP.withdrawParameter]) : bool => { - Test.set_source(s); - let status = Test.transfer_to_contract(rollupContr, Withdraw(withdrawParam), 0 as tez); - return match(status,{ - Success: (_ : nat) => false, - Fail: ( tee : test_exec_error ) => - match(tee,{ - Other: (msg : string) => {Test.log("ERROR Other : "+msg) ; return false}, - Balance_too_low : (_record : [ address , tez , tez ]) => {Test.log("ERROR Balance_too_low") ; return false}, - Rejected: (s:[michelson_program , address])=>{ Test.log(s[0]) ; return true } }) - }); - }; +const _ = Test.log(Test.get_balance(sender1)); + +const _ = Test.log(sender1); + +const sender2: address = Test.nth_bootstrap_account(2); + +const _ = Test.log("Sender 2 has balance : "); + +const _ = Test.log(Test.get_balance(sender2)); + +const _ = Test.log(sender2); + +const sender3: address = Test.nth_bootstrap_account(3); + +const _ = Test.log("Sender 3 has balance : "); + +const _ = Test.log(Test.get_balance(sender3)); + +const _ = Test.log(sender3); + +const _ = Test.set_baker(treasury); + +const _ = Test.set_source(treasury); + +//mock rollup origination + +const [trollupaddr, rollupContrMichelson, _] = + Test.originate( + ROLLUP.main, + Map.empty as map>, + 0 as tez + ); +const rollupContr = Test.to_contract(trollupaddr); - const _testPendingWithdrawDEKU = ([s,faPendingWithdraw] : [address,CONTRACT.faPendingParameter]) : bool => { - Test.set_source(s); - - - let faStorage : FA12.storage = Test.get_storage (tfaaddr); - Test.log(faStorage); - - //check current value before testing - let oldTreasuryBalance : nat = match(Big_map.find_opt(contrStorage.treasuryAddress,faStorage.tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - Test.log("oldTreasuryBalance"); - Test.log(oldTreasuryBalance); - - - //check current value before testing - let oldSenderBalance : tez = Test.get_balance(s); - Test.log("oldSenderBalance"); - Test.log(oldSenderBalance); - let oldContractBalance : tez = Test.get_balance(Tezos.address(contr)); - Test.log("oldContractBalance"); - Test.log(oldContractBalance); - - let oldSenderTokenBalance : nat = match(Big_map.find_opt(s,faStorage.tokens),{None:()=>(0 as nat),Some:(n:nat)=>n}); - Test.log("oldSenderTokenBalance"); - Test.log(oldSenderTokenBalance); - let oldContractTokenBalance : nat = match(Big_map.find_opt(contrAddress,faStorage.tokens),{None:()=>(0 as nat),Some:(n:nat)=>n}); - Test.log("oldContractTokenBalance"); - Test.log(oldContractTokenBalance); - - // not possible to do, so display it on log - //let oldTicketQty = Test.log(rollupStore); - Test.log("*** MANUAL CHECK : rollupStore before any test is launched ***"); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - Test.log(rollupStore); - - Test.log("faPendingWithdraw"); - Test.log(faPendingWithdraw); - let status = Test.transfer_to_contract(contr, WithdrawPendingDEKU(faPendingWithdraw), 0 as tez); - Test.log(status); - //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); - let rollupStore : michelson_program = Test.get_storage_of_address(rollupAddress); - Test.log("*** MANUAL CHECK : rollupStore after any test is launched ***"); - Test.log(rollupStore); - //check balances for contract and user - - const qty : nat = faPendingWithdraw[1].amountToTransfer; - Test.log(qty); - - let newfastorage : FA12.storage = Test.get_storage(tfaaddr); +const rollupAddress = Tezos.address(rollupContr); + +const _ = Test.log("rollup contract deployed with values : "); + +const _ = Test.log(rollupContr); + +//fa1.2 origination + +const fabalance: nat = 4200 as nat; + +const [tfaaddr, _, _] = + Test.originate( + FA12.main, //prepare allowance of 42 for later + { + tokens: Big_map.literal(list([[sender3, fabalance]])) as + big_map, + allowances: Big_map.literal(list([[[sender3, treasury], (42 as nat)]])) as + big_map<[address, address], nat>, + total_amount: fabalance + }, + 0 as tez + ); + +const faContr = Test.to_contract(tfaaddr); + +const faAddress = Tezos.address(faContr); + +const _ = Test.log("fa contract deployed with values : "); + +const _ = Test.log(faContr); + +const _ = Test.log(Test.get_storage_of_address(faAddress)); + +//contract origination + +const contrStorage = + { + treasuryAddress: treasury, + faPendingDeposits: Map.empty as CONTRACT.faPendingMapType, + faPendingWithdrawals: Map.empty as CONTRACT.faPendingMapType + }; + +const [taddr, _, _] = Test.originate(CONTRACT.main, contrStorage, 0 as tez); + +const contr = Test.to_contract(taddr); + +const contrAddress = Tezos.address(contr); + +const _ = Test.log("contract deployed with values : "); + +const _ = Test.log(contr); + +const xTZType: bytes = Bytes.pack(XTZ()); + +const fAType: bytes = Bytes.pack(FA(faAddress)); + +// FUNCTIONS + +const _testDeposit = ( + [s, depositOp, xTZToCheck, fA12ToCheck] + : [address, CONTRACT.depositOp, nat, nat] +): bool => { + Test.set_source(s); + let faStorage: FA12.storage = Test.get_storage(tfaaddr); + //check current value before testing + + let oldSenderBalance = Test.get_balance(s); + let oldContractBalance = Test.get_balance(Tezos.address(contr)); + let oldTreasuryBalance = + match( + Big_map.find_opt(contrStorage.treasuryAddress, faStorage.tokens) as + option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + // not possible to do, so display it on log + //let oldTicketQty = Test.log(rollupStore); + + Test. + log("*** MANUAL CHECK : rollupStore before any test is launched ***"); + let rollupStore: michelson_program = + Test.get_storage_of_address(rollupAddress); + Test.log(rollupStore); + Test.log(depositOp); + let status = + Test.transfer_to_contract( + contr, + Deposit(depositOp), + xTZToCheck * (1 as mutez) + ); + Test.log(status); + //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); + + let rollupStore2: michelson_program = + Test.get_storage_of_address(rollupAddress); + let _l2adr = + match( + depositOp, + { + XTZ_OP: (xtzOp: xtzOp) => { + //check ticket on rollup + + Test. + log("*** MANUAL CHECK : rollupStore after test ***"); + Test.log(rollupStore2); + Test.log( + ["*** MANUAL CHECK : expected additional ticket qty : ", xTZToCheck] + ); + Test.log( + [ + "*** MANUAL CHECK : actual ticket qty for inbox rollup : ", + "DO COMPARE MANUALLY" + ] + ); + //check contract balance. It should increase + + assert( + Test.get_balance(Tezos.address(contr)) == + oldContractBalance + (xTZToCheck * (1 as mutez)) + ); + //check sender balance. It should decrease + + assert( + Test.get_balance(s) <= + Option.unopt(oldSenderBalance - (xTZToCheck * (1 as mutez))) + ); + return xtzOp.l2Type + }, + FA_OP: (faOp: faOp) => { + //check FA12 tokens ownership + + let contrStorage: CONTRACT.storage = Test.get_storage(taddr); + let treasuryBalance = + match( + Big_map.find_opt(contrStorage.treasuryAddress, faStorage.tokens) as + option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + let senderBalance = + match( + Big_map.find_opt(s, faStorage.tokens) as option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + assert(treasuryBalance == oldTreasuryBalance); // transfer of token not yet done by the treasury + assert(senderBalance == fabalance); // transfer of token not yet done by the treasury + //check ticket on rollup + + Test. + log("*** MANUAL CHECK : rollupStore after test ***"); + Test.log(rollupStore2); + Test.log( + [ + "*** MANUAL CHECK : expected additional ticket qty : ", + fA12ToCheck + ] + ); + Test.log( + [ + "*** MANUAL CHECK : actual ticket qty for inbox rollup : ", + "DO COMPARE MANUALLY" + ] + ); + //check contract balance. It should not move + + assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance); + return faOp.l2Type + } + } + ); + return true +}; + +const _testPendingDeposit = ( + [s, faPendingDeposit]: [address, CONTRACT.faPendingParameter] +): bool => { + Test.set_source(s); + let faStorage: FA12.storage = Test.get_storage(tfaaddr); + //check current value before testing + + let oldContractBalance = Test.get_balance(Tezos.address(contr)); + let oldTreasuryBalance = + match( + Big_map.find_opt(contrStorage.treasuryAddress, faStorage.tokens) as + option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + // not possible to do, so display it on log + //let oldTicketQty = Test.log(rollupStore); + + Test. + log("*** MANUAL CHECK : rollupStore before any test is launched ***"); + let rollupStore: michelson_program = + Test.get_storage_of_address(rollupAddress); + Test.log(rollupStore); + Test.log(faPendingDeposit); + let status = + Test.transfer_to_contract( + contr, + PendingDeposit(faPendingDeposit), + 0 as mutez + ); + Test.log(status); + //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); + + let rollupStore2: michelson_program = + Test.get_storage_of_address(rollupAddress); + //check FA1.2 tokens ownership + + let faStorage2: FA12.storage = Test.get_storage(tfaaddr); + let treasuryBalance = + match( + Big_map.find_opt(contrStorage.treasuryAddress, faStorage2.tokens) as + option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + let _senderBalance = + match( + Big_map.find_opt(s, faStorage2.tokens) as option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + assert(oldTreasuryBalance == treasuryBalance); //transfer should be done before this call + //check ticket on rollup + + Test. + log("*** MANUAL CHECK : rollupStore after test ***"); + Test.log(rollupStore2); + Test.log( + [ + "*** MANUAL CHECK : actual ticket qty for inbox rollup : ", + "DO COMPARE MANUALLY" + ] + ); + //check contract balance. It should not move + + assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance); + return true +}; + +const _testDepositFail = ( + [s, depositOp, tezToPay, message]: [address, CONTRACT.depositOp, nat, string] +): bool => { + Test.set_source(s); + Test.log( + "Testing error to fail : " + Option.unopt(Map.find_opt(message, errorMap)) + ); + return assert_failure( + Test.transfer_to_contract( + contr, + (Deposit(depositOp)), + tezToPay * (1 as tez) + ), + message + ) +}; + +const _testPendingDepositFail = ( + [s, faPendingDeposit, message]: [address, CONTRACT.faPendingParameter, string] +): bool => { + Test.set_source(s); + Test.log( + "Testing error to fail : " + Option.unopt(Map.find_opt(message, errorMap)) + ); + return assert_failure( + Test.transfer_to_contract( + contr, + (PendingDeposit(faPendingDeposit)), + 0 as tez + ), + message + ) +}; + +const _testWithdrawDEKU = ( + [s, withdrawParam, remainingBalanceToCheckOncontract, _remainingCtezQuantity] + : [address, ROLLUP.withdrawParameter, tez, nat] +): bool => { + Test.set_source(s); + let faStorage: FA12.storage = Test.get_storage(tfaaddr); + Test.log(faStorage); + //check current value before testing + + let oldTreasuryBalance = + match( + Big_map.find_opt(contrStorage.treasuryAddress, faStorage.tokens) as + option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + //check current value before testing + + let oldSenderBalance: tez = Test.get_balance(s); + Test.log("oldSenderBalance"); + Test.log(oldSenderBalance); + let oldContractBalance: tez = Test.get_balance(Tezos.address(contr)); + Test.log("oldContractBalance"); + Test.log(oldContractBalance); + let oldSenderTokenBalance: nat = + match( + Big_map.find_opt(s, faStorage.tokens), + { None: () => (0 as nat), Some: (n: nat) => n } + ); + Test.log("oldSenderTokenBalance"); + Test.log(oldSenderTokenBalance); + let oldContractTokenBalance: nat = + match( + Big_map.find_opt(contrAddress, faStorage.tokens), + { None: () => (0 as nat), Some: (n: nat) => n } + ); + Test.log("oldContractTokenBalance"); + Test.log(oldContractTokenBalance); + // not possible to do, so display it on log + //let oldTicketQty = Test.log(rollupStore); + + Test. + log("*** MANUAL CHECK : rollupStore before any test is launched ***"); + let rollupStore: michelson_program = + Test.get_storage_of_address(rollupAddress); + Test.log(rollupStore); + Test.log("withdrawParam"); + Test.log(withdrawParam); + let status = + Test.transfer_to_contract(rollupContr, Withdraw(withdrawParam), 0 as tez); + Test.log(status); + //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); + + let rollupStore2: michelson_program = + Test.get_storage_of_address(rollupAddress); + Test.log("*** MANUAL CHECK : rollupStore after any test is launched ***"); + Test.log(rollupStore2); + //check balances for contract and user + + const ticketType: bytes = withdrawParam[1].data; + Test.log(ticketType); + const qty: nat = withdrawParam[1].amount; + Test.log(qty); + if (ticketType == xTZType) { + //check contract balance. It should decrease + + assert( + Test.get_balance(Tezos.address(contr)) == + remainingBalanceToCheckOncontract + ); + assert( + remainingBalanceToCheckOncontract == + Option.unopt(oldContractBalance - (qty * (1 as mutez))) + ); + //check sender balance. It should increase + + assert(Test.get_balance(s) <= (oldSenderBalance + (qty * (1 as tez)))); + return true + } else if (ticketType == fAType) { + let newfastorage: FA12.storage = Test.get_storage(tfaaddr); Test.log(newfastorage); //check contract balance. It should equal to same value - assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance ); - //check treasury token balance, it should be the same until Treasury is doing manually last final transfer of token himself - assert( oldTreasuryBalance == match(Big_map.find_opt((Test.get_storage(taddr)).treasuryAddress,newfastorage.tokens),{None:()=>(0 as nat),Some:(n:nat)=>n})); - return true; + + assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance); + //check sender token balance, it should be the same + + assert( + oldSenderTokenBalance == + match( + Big_map.find_opt(s, newfastorage.tokens), + { None: () => (0 as nat), Some: (n: nat) => n } + ) + ); + //check treasury token balance, it should be the same + + assert( + oldTreasuryBalance == + match( + Big_map.find_opt( + (Test.get_storage(taddr)).treasuryAddress, + newfastorage.tokens + ), + { None: () => (0 as nat), Some: (n: nat) => n } + ) + ); + return true + } else { + Test.log("Cannot find the correct ticketType"); + return false + } +}; + +const _testWithdrawFail = ( + [s, withdrawParam]: [address, ROLLUP.withdrawParameter] +): bool => { + Test.set_source(s); + let status = + Test.transfer_to_contract(rollupContr, Withdraw(withdrawParam), 0 as tez); + return match( + status, + { + Success: (_: nat) => false, + Fail: (tee: test_exec_error) => + match( + tee, + { + Other: (msg: string) => { + Test.log("ERROR Other : " + msg); + return false + }, + Balance_too_low: (_record: [address, tez, tez]) => { + Test.log("ERROR Balance_too_low"); + return false + }, + Rejected: (s: [michelson_program, address]) => { + Test.log(s[0]); + return true + } + } + ) + } + ) +}; + +const _testPendingWithdrawDEKU = ( + [s, faPendingWithdraw]: [address, CONTRACT.faPendingParameter] +): bool => { + Test.set_source(s); + let faStorage: FA12.storage = Test.get_storage(tfaaddr); + Test.log(faStorage); + //check current value before testing + + let oldTreasuryBalance: nat = + match( + Big_map.find_opt(contrStorage.treasuryAddress, faStorage.tokens) as + option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + Test.log("oldTreasuryBalance"); + Test.log(oldTreasuryBalance); + //check current value before testing + + let oldSenderBalance: tez = Test.get_balance(s); + Test.log("oldSenderBalance"); + Test.log(oldSenderBalance); + let oldContractBalance: tez = Test.get_balance(Tezos.address(contr)); + Test.log("oldContractBalance"); + Test.log(oldContractBalance); + let oldSenderTokenBalance: nat = + match( + Big_map.find_opt(s, faStorage.tokens), + { None: () => (0 as nat), Some: (n: nat) => n } + ); + Test.log("oldSenderTokenBalance"); + Test.log(oldSenderTokenBalance); + let oldContractTokenBalance: nat = + match( + Big_map.find_opt(contrAddress, faStorage.tokens), + { None: () => (0 as nat), Some: (n: nat) => n } + ); + Test.log("oldContractTokenBalance"); + Test.log(oldContractTokenBalance); + // not possible to do, so display it on log + //let oldTicketQty = Test.log(rollupStore); + + Test. + log("*** MANUAL CHECK : rollupStore before any test is launched ***"); + let rollupStore: michelson_program = + Test.get_storage_of_address(rollupAddress); + Test.log(rollupStore); + Test.log("faPendingWithdraw"); + Test.log(faPendingWithdraw); + let status = + Test.transfer_to_contract( + contr, + WithdrawPendingDEKU(faPendingWithdraw), + 0 as tez + ); + Test.log(status); + //FIXME, we cannot decompile a ticket => let rollupStore : rollupStorage = Test.get_storage(trollupaddr); + + let rollupStore2: michelson_program = + Test.get_storage_of_address(rollupAddress); + Test.log("*** MANUAL CHECK : rollupStore after any test is launched ***"); + Test.log(rollupStore2); + //check balances for contract and user + + const qty: nat = faPendingWithdraw[1].amountToTransfer; + Test.log(qty); + let newfastorage: FA12.storage = Test.get_storage(tfaaddr); + Test.log(newfastorage); + //check contract balance. It should equal to same value + + assert(Test.get_balance(Tezos.address(contr)) == oldContractBalance); + //check treasury token balance, it should be the same until Treasury is doing manually last final transfer of token himself + + assert( + oldTreasuryBalance == + match( + Big_map.find_opt( + (Test.get_storage(taddr)).treasuryAddress, + newfastorage.tokens + ), + { None: () => (0 as nat), Some: (n: nat) => n } + ) + ); + return true +}; + +const _testPendingWithdrawFailDEKU = ( + [s, faPendingParameter, message] + : [address, CONTRACT.faPendingParameter, string] +): bool => { + Test.set_source(s); + Test.log( + "Testing error to fail : " + Option.unopt(Map.find_opt(message, errorMap)) + ); + return assert_failure( + Test.transfer_to_contract( + contr, + WithdrawPendingDEKU(faPendingParameter), + 0 as tez + ), + message + ) +}; + +//********** TESTS *************/ + +const sender2AddrType: CONTRACT.l2Type = L2_DEKU(sender2); + +const sender3AddrType: CONTRACT.l2Type = L2_DEKU(sender3); + +const sender4AddrType: CONTRACT.l2Type = L2_DEKU(treasury); + +//XTZ deposit + +let xtzOp: CONTRACT.xtzOp = + { + amountToTransfer: 42000000 as nat, + rollupAddress: rollupAddress as address, + l2Type: sender2AddrType as CONTRACT.l2Type }; +const _ = + Test.log( + "*********************** testSender1Deposit42XTZToSender2 ***********************" + ); - const _testPendingWithdrawFailDEKU = ([s,faPendingParameter,message] : [address,CONTRACT.faPendingParameter,string]) : bool => { - Test.set_source(s); - Test.log("Testing error to fail : "+ Option.unopt(Map.find_opt(message,errorMap))); - return assert_failure(Test.transfer_to_contract(contr, WithdrawPendingDEKU(faPendingParameter), 0 as tez),message); - }; - - //********** TESTS *************/ - const sender2AddrType : CONTRACT.l2Type = L2_DEKU(sender2); - const sender3AddrType : CONTRACT.l2Type = L2_DEKU(sender3); - const sender4AddrType : CONTRACT.l2Type = L2_DEKU(treasury); //FIXME to have a real L2 address here later - - - //XTZ deposit - let xtzOp : CONTRACT.xtzOp = { - amountToTransfer: 42000000 as nat, - rollupAddress: rollupAddress as address, - l2Type: sender2AddrType as CONTRACT.l2Type - }; - - const _ = Test.log("*********************** testSender1Deposit42XTZToSender2 ***********************"); - const testSender1Deposit42XTZToSender2 = _testDeposit(sender1,XTZ_OP(xtzOp),xtzOp.amountToTransfer,0 as nat); - - const _ = Test.log("*********************** testSender1DepositXTZBadAmount ***********************"); - let xtzOp1 : CONTRACT.xtzOp = {...xtzOp,amountToTransfer:0 as nat}; - const testSender1DepositXTZBadAmount = _testDepositFail(sender1,XTZ_OP(xtzOp1),0 as nat,"0"); - - const _ = Test.log("*********************** testSender1DepositNotEnoughXTZ ***********************"); - let xtzOp2 : CONTRACT.xtzOp = {...xtzOp1,amountToTransfer:xtzOp.amountToTransfer}; - const testSender1DepositNotEnoughXTZ = _testDepositFail(sender1,XTZ_OP(xtzOp2),0 as nat,"3"); - - const _ = Test.log("*********************** testSender1DepositXTZInvalidRollupAddress ***********************"); - let xtzOp3 : CONTRACT.xtzOp = {...xtzOp2,rollupAddress:sender2}; - const testSender1DepositXTZInvalidRollupAddress = _testDepositFail(sender1,XTZ_OP(xtzOp3),xtzOp.amountToTransfer,"11"); - - //FA1.2 deposit - let faOp : CONTRACT.faOp = { +const testSender1Deposit42XTZToSender2 = + _testDeposit(sender1, XTZ_OP(xtzOp), xtzOp.amountToTransfer, 0 as nat); + +const _ = + Test.log( + "*********************** testSender1DepositXTZBadAmount ***********************" + ); + +let xtzOp1: CONTRACT.xtzOp = { ...xtzOp, amountToTransfer: 0 as nat }; + +const testSender1DepositXTZBadAmount = + _testDepositFail(sender1, XTZ_OP(xtzOp1), 0 as nat, "0"); + +const _ = + Test.log( + "*********************** testSender1DepositNotEnoughXTZ ***********************" + ); + +let xtzOp2: CONTRACT.xtzOp = + { ...xtzOp1, amountToTransfer: xtzOp.amountToTransfer }; + +const testSender1DepositNotEnoughXTZ = + _testDepositFail(sender1, XTZ_OP(xtzOp2), 0 as nat, "3"); + +const _ = + Test.log( + "*********************** testSender1DepositXTZInvalidRollupAddress ***********************" + ); + +let xtzOp3: CONTRACT.xtzOp = { ...xtzOp2, rollupAddress: sender2 }; + +const testSender1DepositXTZInvalidRollupAddress = + _testDepositFail(sender1, XTZ_OP(xtzOp3), xtzOp.amountToTransfer, "11"); + +//FA1.2 deposit + +let faOp: CONTRACT.faOp = + { faAddress: faAddress, amountToTransfer: 42 as nat, rollupAddress: rollupAddress, l2Type: sender3AddrType }; - let faPendingDeposit : CONTRACT.faPendingParameter = [sender3,faOp]; +let faPendingDeposit: CONTRACT.faPendingParameter = [sender3, faOp]; + +const _ = + Test.log( + "*********************** testSender3Deposit42FAToSender3 ***********************" + ); + +const testSender3Deposit42FAToSender3 = + _testDeposit(sender3, FA_OP(faOp), 0 as nat, faOp.amountToTransfer); - const _ = Test.log("*********************** testSender3Deposit42FAToSender3 ***********************"); - const testSender3Deposit42FAToSender3 = _testDeposit(sender3,FA_OP(faOp),0 as nat, faOp.amountToTransfer); +const _ = + Test.log( + "*********************** testSender3PendingDepositNotTreasury ***********************" + ); - const _ = Test.log("*********************** testSender3PendingDepositNotTreasury ***********************"); - const testSender3PendingDepositNotTreasury = _testPendingDepositFail(sender3,faPendingDeposit,"9"); +const testSender3PendingDepositNotTreasury = + _testPendingDepositFail(sender3, faPendingDeposit, "9"); - const _ = Test.log("*********************** testTreasuryPendingDeposit42FAToSender3 ***********************"); - //treasury is doing the transfer of token himself - const _ = Test.log(Test.transfer_to_contract(faContr, TransferFA12({from : sender3,to_ : treasury, value : (42 as nat)}), 0 as mutez)); - let senderBalance = match(Big_map.find_opt(sender3,(Test.get_storage (tfaaddr)).tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - const _ = assert_with_error(senderBalance == abs(fabalance - faOp.amountToTransfer),"User balance for FA12 is not correct"); - const testTreasuryPendingDeposit42FAToSender3 = _testPendingDeposit(treasury,faPendingDeposit); +const _ = + Test.log( + "*********************** testTreasuryPendingDeposit42FAToSender3 ***********************" + ); - const _ = Test.log("*********************** testSender3DepositFABadAmount ***********************"); - const faOp1 : CONTRACT.faOp = {...faOp,amountToTransfer:0 as nat}; - const testSender3DepositFABadAmount = _testDepositFail(sender3,FA_OP(faOp1),0 as nat,"0"); +//treasury is doing the transfer of token himself - const _ = Test.log("*********************** testSender3DepositFAInvalidRollupAddress ***********************"); - const faOp2 : CONTRACT.faOp = {...faOp,rollupAddress:sender2}; - const testSender3DepositFAInvalidRollupAddress = _testDepositFail(sender3,FA_OP(faOp2),0 as nat,"11"); +const _ = + Test.log( + Test.transfer_to_contract( + faContr, + TransferFA12({ from_: sender3, to_: treasury, value: (42 as nat) }), + 0 as mutez + ) + ); - //withdraw (will take into account previous deposits tests) ****************************************************** +let senderBalance = + match( + Big_map.find_opt(sender3, (Test.get_storage(tfaaddr)).tokens) as option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); - //XTZ +const _ = + assert_with_error( + senderBalance == abs(fabalance - faOp.amountToTransfer), + "User balance for FA12 is not correct" + ); - //get withdraw entrypoint of contract - let ticketClaim : ROLLUP.ticketClaim = { - amount : 40000000 as nat, - data : xTZType, +const testTreasuryPendingDeposit42FAToSender3 = + _testPendingDeposit(treasury, faPendingDeposit); + +const _ = + Test.log( + "*********************** testSender3DepositFABadAmount ***********************" + ); + +const faOp1: CONTRACT.faOp = { ...faOp, amountToTransfer: 0 as nat }; + +const testSender3DepositFABadAmount = + _testDepositFail(sender3, FA_OP(faOp1), 0 as nat, "0"); + +const _ = + Test.log( + "*********************** testSender3DepositFAInvalidRollupAddress ***********************" + ); + +const faOp2: CONTRACT.faOp = { ...faOp, rollupAddress: sender2 }; + +const testSender3DepositFAInvalidRollupAddress = + _testDepositFail(sender3, FA_OP(faOp2), 0 as nat, "11"); + +//withdraw (will take into account previous deposits tests) ****************************************************** +//XTZ +//get withdraw entrypoint of contract + +let ticketClaim: ROLLUP.ticketClaim = + { + amount: 40000000 as nat, + data: xTZType, id: 0 as nat, owner: sender2, ticketer: contrAddress }; - let withdrawParam : ROLLUP.withdrawParameter = [ Test.to_entrypoint("withdrawDEKU",taddr) as contract>, ticketClaim ,0x00 , list([]) as list<[bytes,bytes]>]; - const _ = Test.log("*********************** testSender2Withdraw42XTZ ***********************"); - let testSender2WithdrawPartial40XTZ = _testWithdrawDEKU(sender2,withdrawParam,2000000 as mutez, 0 as nat); +let withdrawParam: ROLLUP.withdrawParameter = [ + Test.to_entrypoint("withdrawDEKU", taddr) as contract>, + ticketClaim, + 0x00, + list([]) as list<[bytes, bytes]> +]; + +const _ = + Test.log( + "*********************** testSender2Withdraw42XTZ ***********************" + ); + +let testSender2WithdrawPartial40XTZ = + _testWithdrawDEKU(sender2, withdrawParam, 2000000 as mutez, 0 as nat); + +const _ = + Test.log( + "*********************** testSender2WithdrawTooMuch ***********************" + ); - const _ = Test.log("*********************** testSender2WithdrawTooMuch ***********************"); - let testSender2WithdrawTooMuch = _testWithdrawFail(sender2,withdrawParam); +let testSender2WithdrawTooMuch = _testWithdrawFail(sender2, withdrawParam); - const _ = Test.log("*********************** testSender1WithdrawCannotClaim ***********************"); - let testSender1WithdrawCannotClaim = _testWithdrawFail(sender1,withdrawParam); +const _ = + Test.log( + "*********************** testSender1WithdrawCannotClaim ***********************" + ); - const _ = Test.log("*********************** testSender2WithdrawFinal2XTZ ***********************"); - let ticketClaim2 : ROLLUP.ticketClaim = { - amount : 2000000 as nat, - data : xTZType, +let testSender1WithdrawCannotClaim = _testWithdrawFail(sender1, withdrawParam); + +const _ = + Test.log( + "*********************** testSender2WithdrawFinal2XTZ ***********************" + ); + +let ticketClaim2: ROLLUP.ticketClaim = + { + amount: 2000000 as nat, + data: xTZType, id: 0 as nat, owner: sender2, ticketer: contrAddress }; - let withdrawParam2 : ROLLUP.withdrawParameter = [ Test.to_entrypoint("withdrawDEKU",taddr) as contract>, ticketClaim2 ,0x00 , list([]) as list<[bytes,bytes]>]; - let testSender2WithdrawFinal2XTZ = _testWithdrawDEKU(sender2,withdrawParam2,0 as mutez, 0 as nat); - const _ = Test.log("*********************** testSender2WithdrawNoMoreXTZ ***********************"); - let testSender2WithdrawNoMoreXTZ = _testWithdrawFail(sender2,withdrawParam); +let withdrawParam2: ROLLUP.withdrawParameter = [ + Test.to_entrypoint("withdrawDEKU", taddr) as contract>, + ticketClaim2, + 0x00, + list([]) as list<[bytes, bytes]> +]; + +let testSender2WithdrawFinal2XTZ = + _testWithdrawDEKU(sender2, withdrawParam2, 0 as mutez, 0 as nat); - // FA12 1.2 +const _ = + Test.log( + "*********************** testSender2WithdrawNoMoreXTZ ***********************" + ); - let ticketClaim3 : ROLLUP.ticketClaim = { - amount : 42 as nat, - data : fAType, +const testSender2WithdrawNoMoreXTZ = _testWithdrawFail(sender2, withdrawParam); + +// FA12 1.2 + +const ticketClaim3: ROLLUP.ticketClaim = + { + amount: 42 as nat, + data: fAType, id: 0 as nat, owner: sender3, ticketer: contrAddress }; - let withdrawParam3 : ROLLUP.withdrawParameter = [ Test.to_entrypoint("withdrawDEKU",taddr) as contract>, ticketClaim3 ,0x00 , list([]) as list<[bytes,bytes]>]; - let faPendingWithdraw : CONTRACT.faPendingParameter = [sender3,faOp]; +const withdrawParam3: ROLLUP.withdrawParameter = [ + Test.to_entrypoint("withdrawDEKU", taddr) as contract>, + ticketClaim3, + 0x00, + list([]) as list<[bytes, bytes]> +]; + +const faPendingWithdraw: CONTRACT.faPendingParameter = [sender3, faOp]; + +const _ = + Test.log( + "*********************** testSender3WithdrawAll42CTEZ ***********************" + ); + +let testSender3WithdrawAll42CTEZ = + _testWithdrawDEKU(sender3, withdrawParam3, 0 as mutez, 0 as nat); + +const _ = + Test.log( + "*********************** testSender3PendingWithdrawNotTreasury ***********************" + ); + +const testSender3PendingWithdrawNotTreasury = + _testPendingWithdrawFailDEKU(sender3, faPendingWithdraw, "9"); + +const _ = + Test.log( + "*********************** testTreasuryPendingWithdraw42FAToSender3 ***********************" + ); + +const testTreasuryPendingWithdraw42FAToSender3 = + _testPendingWithdrawDEKU(treasury, faPendingWithdraw); + +//treasury is doing the transfer of token himself + +const _ = + Test.log( + Test.transfer_to_contract( + faContr, + TransferFA12({ from_: treasury, to_: sender3, value: (42 as nat) }), + 0 as mutez + ) + ); + +const senderBalance2 = + match( + Big_map.find_opt(sender3, (Test.get_storage(tfaaddr)).tokens) as option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + +const _ = + assert_with_error( + senderBalance2 == fabalance, + "User balance for FA12 is not correct, it should go back to origination value" + ); + +// FA2 +//fa2 origination + +const fa2balance: nat = 4200 as nat; + +let [tf2aaddr, _, _] = + Test.originate( + FA2.main, //prepare allowance of 42 for later + { + ledger: ( + Big_map.literal( + list( + [ + [ + ["tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address, 0 as nat], + (1000000000000000000 as nat) + ] + ] + ) + ) as big_map<[address, nat], nat> + ), + token_metadata: ( + Big_map.literal( + list( + [ + [ + (0 as nat), + { + token_id: (0 as nat), + token_info: Map.literal( + list( + [ + ["decimals", (0x3132 as bytes)], + ["name", (0x796f757665732075555344 as bytes)], + ["symbol", (0x75555344 as bytes)], + [ + "thumbnailUri", + ( + 0x697066733a2f2f516d627668616e4e437879645a45624775315264716b47334c63704e4776375859734348677a5742586e6d785264 as + bytes + ) + ] + ] + ) + ) + } + ] + ] + ) + ) as big_map }> + ), + operators: Big_map.empty as big_map<[address, address], set>, + token_ids: list([0 as nat]) as list + }, + 0 as mutez + ); + +let fa2Contr = Test.to_contract(tf2aaddr); + +let fa2Address = Tezos.address(fa2Contr); + +let _ = Test.log("fa contract deployed with values : "); + +let _ = Test.log(fa2Contr); + +let _ = Test.log(Test.get_storage_of_address(fa2Address)); + +// add sender3 as an operator to being able to transfer + +let operator: FA2.unit_update = + Add_operator({ owner: sender3, operator: treasury, token_id: 0 as nat }); + +let update_operators_args: FA2.update_operators = list([operator]); + +const _ = + Test.log( + Test.transfer_to_contract( + fa2Contr, + Update_operators(update_operators_args), + 0 as mutez + ) + ); + +// test fa2 + +let ticketClaim4: ROLLUP.ticketClaim = + { + amount: 42 as nat, + data: fAType, + id: 0 as nat, + owner: sender3, + ticketer: contrAddress + }; - const _ = Test.log("*********************** testSender3WithdrawAll42CTEZ ***********************"); - let testSender3WithdrawAll42CTEZ = _testWithdrawDEKU(sender3,withdrawParam3,0 as mutez,0 as nat); +let withdrawParam4: ROLLUP.withdrawParameter = [ + Test.to_entrypoint("withdrawDEKU", taddr) as contract>, + ticketClaim4, + 0x00, + list([]) as list<[bytes, bytes]> +]; - const _ = Test.log("*********************** testSender3PendingWithdrawNotTreasury ***********************"); - const testSender3PendingWithdrawNotTreasury = _testPendingWithdrawFailDEKU(sender3,faPendingWithdraw,"9"); +let faPendingWithdraw2: CONTRACT.faPendingParameter = [sender3, faOp]; - const _ = Test.log("*********************** testTreasuryPendingWithdraw42FAToSender3 ***********************"); - const testTreasuryPendingWithdraw42FAToSender3 = _testPendingWithdrawDEKU(treasury,faPendingWithdraw); +const _ = + Test.log( + "*********************** testSender3WithdrawAll42CTEZ fa2 ***********************" + ); - //treasury is doing the transfer of token himself - const _ = Test.log(Test.transfer_to_contract(faContr, TransferFA12({from : treasury,to_ : sender3, value : (42 as nat)}), 0 as mutez)); - let senderBalance2 = match(Big_map.find_opt(sender3,(Test.get_storage (tfaaddr)).tokens) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - const _ = assert_with_error(senderBalance2 == fabalance,"User balance for FA12 is not correct, it should go back to origination value"); +let testSender3WithdrawAll42CTEZ2 = + _testWithdrawDEKU(sender3, withdrawParam4, 0 as mutez, 0 as nat); - // FA2 +const _ = + Test.log( + "*********************** testSender3PendingWithdrawNotTreasury fa2 ***********************" + ); - //fa2 origination - let fa2balance :nat = 4200 as nat; - let [tf2aaddr, _, _] = Test.originate(FA2.main, //prepare allowance of 42 for later - { - ledger : ( Big_map.literal( list([ - [ ["tz1VApBuWHuaTfDHtKzU3NBtWFYsxJvvWhYk" as address, 0 as nat] , (1000000000000000000 as nat)]]) - ) as big_map<[address,nat],nat> ), - token_metadata : ( Big_map.literal ( list([ - [ (0 as nat) , - {token_id : (0 as nat), - token_info : Map.literal ( list([ - ["decimals", (0x3132 as bytes)] , - ["name", (0x796f757665732075555344 as bytes) ], - ["symbol", (0x75555344 as bytes) ], - ["thumbnailUri", (0x697066733a2f2f516d627668616e4e437879645a45624775315264716b47334c63704e4776375859734348677a5742586e6d785264 as bytes)] - ])) - }] ]) ) as big_map}>), - operators : Big_map.empty as big_map<[address, address], set> , - token_ids : list([0 as nat]) as list - }, 0 as mutez); - let fa2Contr = Test.to_contract(tf2aaddr); - let fa2Address = Tezos.address(fa2Contr); - let _ = Test.log("fa contract deployed with values : "); - let _ = Test.log(fa2Contr); - let _ = Test.log(Test.get_storage_of_address(fa2Address)); - - // add sender3 as an operator to being able to transfer - let operator : FA2.unit_update = - Add_operator( - { - owner : sender3, - operator : treasury, - token_id : 0 as nat - } - ) - let update_operators_args : FA2.update_operators = list([operator]); - const _ = Test.log(Test.transfer_to_contract(fa2Contr,Update_operators(update_operators_args),0 as mutez)); +const testSender3PendingWithdrawNotTreasury2 = + _testPendingWithdrawFailDEKU(sender3, faPendingWithdraw2, "9"); - // test fa2 - let ticketClaim4 : ROLLUP.ticketClaim = { - amount : 42 as nat, - data : fAType, - id: 0 as nat, - owner: sender3, - ticketer: contrAddress - }; - let withdrawParam4 : ROLLUP.withdrawParameter = [ Test.to_entrypoint("withdrawDEKU",taddr) as contract>, ticketClaim4 ,0x00 , list([]) as list<[bytes,bytes]>]; +const _ = + Test.log( + "*********************** testTreasuryPendingWithdraw42FAToSender3 fa2 ***********************" + ); - let faPendingWithdraw2 : CONTRACT.faPendingParameter = [sender3,faOp]; +const testTreasuryPendingWithdraw42FAToSender32 = + _testPendingWithdrawDEKU(treasury, faPendingWithdraw2); - const _ = Test.log("*********************** testSender3WithdrawAll42CTEZ fa2 ***********************"); - let testSender3WithdrawAll42CTEZ2 = _testWithdrawDEKU(sender3,withdrawParam4,0 as mutez,0 as nat); +let txs: list = + list([{ to_: sender3, token_id: (0 as nat), quantity: (42 as nat) }]); - const _ = Test.log("*********************** testSender3PendingWithdrawNotTreasury fa2 ***********************"); - const testSender3PendingWithdrawNotTreasury2 = _testPendingWithdrawFailDEKU(sender3,faPendingWithdraw2,"9"); +let transferArg: list = list([{ from_: treasury, tx: txs }]); - const _ = Test.log("*********************** testTreasuryPendingWithdraw42FAToSender3 fa2 ***********************"); - const testTreasuryPendingWithdraw42FAToSender32 = _testPendingWithdrawDEKU(treasury,faPendingWithdraw2); +//treasury is doing the transfer of token himself - let txs : list = list ([ - { - to_ : sender3, - token_id : (0 as nat), - quantity : (42 as nat) - } - ]); - let transferArg : list = list([ - { - from_: treasury, - tx : txs - } - ]); - //treasury is doing the transfer of token himself - const _ = Test.log(Test.transfer_to_contract(fa2Contr, TransferFA2(transferArg), 0 as mutez)); - let senderBalance3 = match(Big_map.find_opt([sender3,0 as nat],(Test.get_storage(tf2aaddr)).ledger) as option, { - Some : (qty: nat)=>qty, - None : () => 0 as nat - }); - const _ = assert_with_error(senderBalance3 == fa2balance,"User balance for FA2 is not correct, it should go back to origination value"); \ No newline at end of file +const _ = + Test.log( + Test.transfer_to_contract(fa2Contr, TransferFA2(transferArg), 0 as mutez) + ); + +let senderBalance3 = + match( + Big_map.find_opt([sender3, 0 as nat], (Test.get_storage(tf2aaddr)).ledger) as + option, + { Some: (qty: nat) => qty, None: () => 0 as nat } + ); + +const _ = + assert_with_error( + senderBalance3 == fa2balance, + "User balance for FA2 is not correct, it should go back to origination value" + ); \ No newline at end of file