diff --git a/integration-tests/contract-originate-and-call-contract-lambda-rec.spec.ts b/integration-tests/contract-originate-and-call-contract-lambda-rec.spec.ts new file mode 100644 index 0000000000..7c580730fb --- /dev/null +++ b/integration-tests/contract-originate-and-call-contract-lambda-rec.spec.ts @@ -0,0 +1,49 @@ +import { Protocols } from "@taquito/taquito"; +import { CONFIGS } from "./config"; +import { recFactApplyStore, recursiveLambda, reduceMap } from "./data/lambda-rec"; + +CONFIGS().forEach(({ lib, rpc, setup, protocol }) => { + const Tezos = lib; + const limanetAndAlpha = protocol === Protocols.PtLimaPtL || protocol === Protocols.ProtoALpha ? test : test.skip; + + describe(`Test deploying and interacting with contracts having recursive lambda through the contract api using: ${rpc}`, () => { + + beforeEach(async (done) => { + await setup(true); + done(); + }) + + limanetAndAlpha('Verify that a contract having the LAMBDA_REC instruction in its code can be deployed', async (done) => { + const deployContract = await Tezos.contract.originate({ + code: recFactApplyStore, + storage: { 0: 3 } + }); + + await deployContract.confirmation(); + expect(deployContract.hash).toBeDefined(); + expect(deployContract.status).toEqual('applied'); + + done(); + }); + + limanetAndAlpha('Verify that a contract entrypoint having a type lambda can be called with a recursive lambda', async (done) => { + const deployContract = await Tezos.contract.originate({ + code: reduceMap, + storage: [1] + }); + + const contract = await deployContract.contract(); + + const op = await contract.methodsObject.default({ + 0: { prim: "Lambda_rec", args: recursiveLambda }, + 1: [1] + }).send(); + + await op.confirmation(); + expect(op.hash).toBeDefined(); + expect(op.status).toEqual('applied'); + + done(); + }); + }); +}) diff --git a/integration-tests/data/lambda-rec.ts b/integration-tests/data/lambda-rec.ts new file mode 100644 index 0000000000..988c53eeb2 --- /dev/null +++ b/integration-tests/data/lambda-rec.ts @@ -0,0 +1,128 @@ +export const recFactApplyStore = `{ storage (or int (lambda int int)); + parameter (or (unit %gen) (int %exec)); + code { UNPAIR; + IF_LEFT{ DROP 2; + LAMBDA_REC (pair unit int) int + { UNPAIR; + DUP 2; + EQ; + IF { PUSH int 1 } + { DUP 2; + DUP 4; + DUP 3; + APPLY; + PUSH int 1; + DUP 3; + SUB; + EXEC; + MUL}; + DIP { DROP 3 }}; + UNIT; + APPLY; + RIGHT int} + { DIP { ASSERT_RIGHT }; + EXEC; + LEFT (lambda int int)}; + NIL operation; + PAIR}}` + +export const reduceMap = `parameter (pair (lambda int int) (list int)); +storage (list int); +code { DIP{NIL int}; + CAR; + DUP; + DIP{CAR; PAIR}; # Unpack data and setup accumulator + CDR; + ITER {PAIR; + DUP; CDAR; + DIP{ DUP; DIP{CDAR}; DUP; + CAR; DIP{CDDR; SWAP}; EXEC; CONS}; + PAIR}; + CDR; DIP{NIL int}; # First reduce + ITER {CONS}; # Reverse + NIL operation; PAIR} # Calling convention` + +export const recursiveLambda = [ + [ + { + "prim": "DUP" + }, + { + "prim": "EQ" + }, + { + "prim": "IF", + "args": [ + [ + { + "prim": "PUSH", + "args": [ + { + "prim": "int" + }, + { + "int": "1" + } + ] + } + ], + [ + { + "prim": "DUP" + }, + { + "prim": "DUP", + "args": [ + { + "int": "3" + } + ] + }, + { + "prim": "PUSH", + "args": [ + { + "prim": "int" + }, + { + "int": "1" + } + ] + }, + { + "prim": "DUP", + "args": [ + { + "int": "4" + } + ] + }, + { + "prim": "SUB" + }, + { + "prim": "EXEC" + }, + { + "prim": "MUL" + } + ] + ] + }, + { + "prim": "DIP", + "args": [ + [ + { + "prim": "DROP", + "args": [ + { + "int": "2" + } + ] + } + ] + ] + } + ] +]; \ No newline at end of file