From 0849b4057d371b03db76fc0a77562e06ffccd2f0 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sat, 14 Sep 2024 08:59:49 -0400 Subject: [PATCH 1/2] callNonClassFunction --- package.json | 1 + src/lib/compiler.ts | 144 ++++-- .../artifacts/FunctionsTest.approval.teal | 86 ++++ .../artifacts/FunctionsTest.arc32.json | 74 +++ .../artifacts/FunctionsTest.arc4.json | 29 ++ .../artifacts/FunctionsTest.arc56_draft.json | 446 ++++++++++++++++++ .../artifacts/FunctionsTest.clear.teal | 1 + tests/contracts/functions.algo.ts | 11 + tests/functions.test.ts | 23 + 9 files changed, 771 insertions(+), 44 deletions(-) create mode 100644 tests/contracts/artifacts/FunctionsTest.approval.teal create mode 100644 tests/contracts/artifacts/FunctionsTest.arc32.json create mode 100644 tests/contracts/artifacts/FunctionsTest.arc4.json create mode 100644 tests/contracts/artifacts/FunctionsTest.arc56_draft.json create mode 100644 tests/contracts/artifacts/FunctionsTest.clear.teal create mode 100644 tests/contracts/functions.algo.ts create mode 100644 tests/functions.test.ts diff --git a/package.json b/package.json index 51b377d2f..58ed8ae70 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "compile-lsig": "bun ./src/bin/tealscript.ts tests/contracts/lsig.algo.ts tests/contracts/artifacts", "compile-inheritance": "bun ./src/bin/tealscript.ts tests/contracts/inheritance.algo.ts tests/contracts/artifacts", "compile-avm11": "bun ./src/bin/tealscript.ts --skip-algod tests/contracts/avm11.algo.ts tests/contracts/artifacts", + "compile-functions": "bun ./src/bin/tealscript.ts tests/contracts/functions.algo.ts tests/contracts/artifacts", "compile-amm": "bun ./src/bin/tealscript.ts examples/amm/amm.algo.ts examples/amm/tealscript_artifacts", "compile-arc75": "bun src/bin/tealscript.ts examples/arc75/arc75.algo.ts examples/arc75/artifacts && algokitgen generate -a examples/arc75/artifacts/ARC75.arc32.json -o examples/arc75/ARC75Client.ts", "compile-auction": "bun ./src/bin/tealscript.ts examples/auction/auction.algo.ts examples/auction/tealscript_artifacts", diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index aa3964ae5..d18e95154 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -488,6 +488,8 @@ export type TEALInfo = { /** @internal */ export default class Compiler { + private pendingSubroutines: ts.FunctionDeclaration[] = []; + static diagsRan: string[] = ['']; private scratch: { [name: string]: { slot?: number; type: TypeInfo; initNode: ts.CallExpression } } = {}; @@ -1464,7 +1466,14 @@ export default class Compiler { this.processNode(node.getArguments()[0]); - const indexInScratch: boolean = this.teal[this.currentProgram].length - preTealLength > 1; + // Get the opcodes that were needed to process the txn index + const opcodes = this.teal[this.currentProgram] + .slice(preTealLength) + .map((t) => t.teal) + .filter((t) => !t.startsWith('//')); + + // If more than one opcode was needed, it will be more efficient to store the index in scratch + const indexInScratch: boolean = opcodes.length > 1; if (indexInScratch) { this.pushVoid(node, `store ${compilerScratch.verifyTxnIndex}`); @@ -2622,19 +2631,19 @@ export default class Compiler { * * @param methods The methods to process */ - preProcessMethods(methods: ts.MethodDeclaration[]) { + preProcessMethods(methods: (ts.MethodDeclaration | ts.FunctionDeclaration)[]) { methods.forEach((node) => { - if (!node.getNameNode().isKind(ts.SyntaxKind.Identifier)) throw Error('Method name must be identifier'); + if (!node.getNameNode()?.isKind(ts.SyntaxKind.Identifier)) throw Error('Method name must be identifier'); + const name = node.getNameNode()!.getText(); const typeNode = node.getReturnType(); - if (typeNode === undefined) - throw Error(`A return type annotation must be defined for ${node.getNameNode().getText()}`); + if (typeNode === undefined) throw Error(`A return type annotation must be defined for ${name}`); const returnType = node.getReturnTypeNode()?.getType() ? this.getTypeInfo(node.getReturnTypeNode()!.getType()) : StackType.void; const sub = { - name: node.getNameNode().getText(), + name, allows: { call: [], create: [] }, nonAbi: { call: [], create: [] }, args: [], @@ -2953,6 +2962,10 @@ export default class Compiler { }); } + while (this.pendingSubroutines.length > 0) { + this.processSubroutine(this.pendingSubroutines.pop()!); + } + this.teal[this.currentProgram] = await this.postProcessTeal(this.teal[this.currentProgram]); this.teal[this.currentProgram] = optimizeTeal(this.teal[this.currentProgram]); this.teal[this.currentProgram] = this.prettyTeal(this.teal[this.currentProgram]); @@ -3034,6 +3047,10 @@ export default class Compiler { } }); + while (this.pendingSubroutines.length > 0) { + this.processSubroutine(this.pendingSubroutines.pop()!); + } + this.teal.clear = await this.postProcessTeal(this.teal.clear); this.teal.clear = optimizeTeal(this.teal.clear); this.teal.clear = this.prettyTeal(this.teal.clear); @@ -3323,8 +3340,14 @@ export default class Compiler { else if (node.isKind(ts.SyntaxKind.IfStatement)) this.processIfStatement(node); else if (node.isKind(ts.SyntaxKind.PrefixUnaryExpression)) this.processUnaryExpression(node); else if (node.isKind(ts.SyntaxKind.BinaryExpression)) this.processBinaryExpression(node); - else if (node.isKind(ts.SyntaxKind.CallExpression)) this.processExpressionChain(node); - else if (node.isKind(ts.SyntaxKind.ExpressionStatement)) this.processExpressionStatement(node); + else if (node.isKind(ts.SyntaxKind.CallExpression)) { + const expr = node.getExpression(); + if (expr.isKind(ts.SyntaxKind.PropertyAccessExpression)) { + this.processExpressionChain(node); + } else { + this.processCallExpression(node); + } + } else if (node.isKind(ts.SyntaxKind.ExpressionStatement)) this.processExpressionStatement(node); else if (node.isKind(ts.SyntaxKind.ReturnStatement)) this.processReturnStatement(node); else if (node.isKind(ts.SyntaxKind.ParenthesizedExpression)) this.processNode(node.getExpression()); else if (node.isKind(ts.SyntaxKind.VariableStatement)) this.processNode(node.getDeclarationList()); @@ -5014,7 +5037,10 @@ export default class Compiler { .map((a) => a.getKind()) .includes(ts.SyntaxKind.ClassDeclaration); - if (!inClass) { + // This is true when we are in a non-class function and the identifier is a function parameter + const isFunctionParam = defNode.getParent()?.isKind(ts.SyntaxKind.FunctionDeclaration); + + if (!inClass && !isFunctionParam) { if (!defNode.isKind(ts.SyntaxKind.VariableDeclaration)) throw Error(); this.processNode(defNode.getInitializerOrThrow()); return; @@ -6168,33 +6194,74 @@ export default class Compiler { if (chain[0].isKind(ts.SyntaxKind.PropertyAccessExpression) && chain[1].isKind(ts.SyntaxKind.CallExpression)) { const methodName = chain[0].getNameNode().getText(); - const preArgsType = this.lastType; - const subroutine = this.subroutines.find((s) => s.name === methodName); - if (!subroutine) throw new Error(`Unknown subroutine ${methodName}`); + this.processCallExpression(chain[1]); + chain.splice(0, 2); + } + } - new Array(...chain[1].getArguments()).reverse().forEach((a, i) => { - const prevTypeHint = this.typeHint; - this.typeHint = subroutine.args[i].type; - this.processNode(a); - this.typeHint = prevTypeHint; - if (this.lastType.kind === 'base' && this.lastType.type.startsWith('unsafe ')) { - this.checkEncoding(a, this.lastType); - if (isSmallNumber(this.lastType)) this.push(a, 'btoi', this.lastType); - } - typeComparison(this.lastType, subroutine.args[i].type); - }); + private processCallExpression(node: ts.CallExpression) { + this.addSourceComment(node); - this.lastType = preArgsType; - const returnTypeStr = typeInfoToABIString(subroutine.returns.type); + const expr = node.getExpression(); + let methodName: string; + if (expr?.isKind(ts.SyntaxKind.PropertyAccessExpression)) { + methodName = expr.getNameNode().getText(); + } else if (expr?.isKind(ts.SyntaxKind.Identifier)) { + methodName = expr.getText(); + + // If this is a custom method + if (this.customMethods[methodName] && this.customMethods[methodName].check(node)) { + this.customMethods[methodName].fn(node); + return; + } + + // If this is an opcode + if (langspec.Ops.map((o) => o.Name).includes(this.opcodeAliases[methodName] ?? methodName)) { + this.processOpcode(node); + return; + } + + // If a txn method like sendMethodCall, sendPayment, etc. + if (TXN_METHODS.includes(methodName)) { + const { returnType, argTypes, name } = this.methodTypeArgsToTypes(node.getTypeArguments()); - let returnType = subroutine.returns.type; - if (returnTypeStr.match(/\d+$/) && !returnTypeStr.match(/^(uint|ufixed)64/)) { - returnType = { kind: 'base', type: `unsafe ${returnTypeStr}` }; + this.processTransaction(node, methodName, node.getArguments()[0], argTypes, returnType, name); + return; } - this.push(chain[1], `callsub ${methodName}`, returnType); - if (this.nodeDepth === 1 && !equalTypes(subroutine.returns.type, StackType.void)) this.pushVoid(chain[1], 'pop'); - chain.splice(0, 2); + + if (this.subroutines.find((s) => s.name === methodName) === undefined) { + const definition = expr.getDefinitionNodes()[0]; + if (!definition.isKind(ts.SyntaxKind.FunctionDeclaration)) throw Error(); + this.preProcessMethods([definition]); + this.pendingSubroutines.push(definition); + } + } else throw new Error(`Invalid parent for call expression: ${expr?.getKindName()} ${expr?.getText()}`); + + const preArgsType = this.lastType; + const subroutine = this.subroutines.find((s) => s.name === methodName); + if (!subroutine) throw new Error(`Unknown subroutine ${methodName}`); + + new Array(...node.getArguments()).reverse().forEach((a, i) => { + const prevTypeHint = this.typeHint; + this.typeHint = subroutine.args[i].type; + this.processNode(a); + this.typeHint = prevTypeHint; + if (this.lastType.kind === 'base' && this.lastType.type.startsWith('unsafe ')) { + this.checkEncoding(a, this.lastType); + if (isSmallNumber(this.lastType)) this.push(a, 'btoi', this.lastType); + } + typeComparison(this.lastType, subroutine.args[i].type); + }); + + this.lastType = preArgsType; + const returnTypeStr = typeInfoToABIString(subroutine.returns.type); + + let returnType = subroutine.returns.type; + if (returnTypeStr.match(/\d+$/) && !returnTypeStr.match(/^(uint|ufixed)64/)) { + returnType = { kind: 'base', type: `unsafe ${returnTypeStr}` }; } + this.push(node, `callsub ${methodName}`, returnType); + if (this.nodeDepth === 1 && !equalTypes(subroutine.returns.type, StackType.void)) this.pushVoid(node, 'pop'); } private methodTypeArgsToTypes(typeArgs: ts.TypeNode[]) { @@ -6384,18 +6451,6 @@ export default class Compiler { return; } - // If a txn method like sendMethodCall, sendPayment, etc. - if (TXN_METHODS.includes(base.getText())) { - if (!chain[0].isKind(ts.SyntaxKind.CallExpression)) - throw Error(`Unsupported ${chain[0].getKindName()} ${chain[0].getText()}`); - - const { returnType, argTypes, name } = this.methodTypeArgsToTypes(chain[0].getTypeArguments()); - - this.processTransaction(node, base.getText(), chain[0].getArguments()[0], argTypes, returnType, name); - chain.splice(0, 1); - return; - } - // If this is a global variable if (base.getText() === 'globals') { if (!chain[0].isKind(ts.SyntaxKind.PropertyAccessExpression)) @@ -6633,8 +6688,9 @@ export default class Compiler { ); } - private processSubroutine(fn: ts.MethodDeclaration) { + private processSubroutine(fn: ts.MethodDeclaration | ts.FunctionDeclaration) { const frameStart = this.teal[this.currentProgram].length; + this.currentSubroutine = this.subroutines.find((s) => s.name === fn.getNameNode()?.getText())!; const sigParams = fn .getSignature() diff --git a/tests/contracts/artifacts/FunctionsTest.approval.teal b/tests/contracts/artifacts/FunctionsTest.approval.teal new file mode 100644 index 000000000..3b51fcccd --- /dev/null +++ b/tests/contracts/artifacts/FunctionsTest.approval.teal @@ -0,0 +1,86 @@ +#pragma version 10 + +// This TEAL was generated by TEALScript v0.101.0 +// https://github.com/algorandfoundation/TEALScript + +// This contract is compliant with and/or implements the following ARCs: [ ARC4 ] + +// The following ten lines of TEAL handle initial program flow +// This pattern is used to make it easy for anyone to parse the start of the program and determine if a specific action is allowed +// Here, action refers to the OnComplete in combination with whether the app is being created or called +// Every possible action for this contract is represented in the switch statement +// If the action is not implemented in the contract, its respective branch will be "*NOT_IMPLEMENTED" which just contains "err" +txn ApplicationID +! +int 6 +* +txn OnCompletion ++ +switch *call_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *create_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED + +*NOT_IMPLEMENTED: + // The requested action is not implemented in this contract. Are you using the correct OnComplete? Did you set your app ID? + err + +// callNonClassFunction(uint64,uint64)uint64 +*abi_route_callNonClassFunction: + // The ABI return prefix + byte 0x151f7c75 + + // b: uint64 + txna ApplicationArgs 2 + btoi + + // a: uint64 + txna ApplicationArgs 1 + btoi + + // execute callNonClassFunction(uint64,uint64)uint64 + callsub callNonClassFunction + itob + concat + log + int 1 + return + +// callNonClassFunction(a: uint64, b: uint64): uint64 +callNonClassFunction: + proto 2 1 + + // tests/contracts/functions.algo.ts:9 + // return nonClassFunction(a, b); + frame_dig -2 // b: uint64 + frame_dig -1 // a: uint64 + callsub nonClassFunction + retsub + +*abi_route_createApplication: + int 1 + return + +*create_NoOp: + method "createApplication()void" + txna ApplicationArgs 0 + match *abi_route_createApplication + + // this contract does not implement the given ABI method for create NoOp + err + +*call_NoOp: + method "callNonClassFunction(uint64,uint64)uint64" + txna ApplicationArgs 0 + match *abi_route_callNonClassFunction + + // this contract does not implement the given ABI method for call NoOp + err + +// nonClassFunction(a: uint64, b: uint64): uint64 +nonClassFunction: + proto 2 1 + + // tests/contracts/functions.algo.ts:4 + // return a + b; + frame_dig -1 // a: uint64 + frame_dig -2 // b: uint64 + + + retsub \ No newline at end of file diff --git a/tests/contracts/artifacts/FunctionsTest.arc32.json b/tests/contracts/artifacts/FunctionsTest.arc32.json new file mode 100644 index 000000000..7d7b587dd --- /dev/null +++ b/tests/contracts/artifacts/FunctionsTest.arc32.json @@ -0,0 +1,74 @@ +{ + "hints": { + "callNonClassFunction(uint64,uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "createApplication()void": { + "call_config": { + "no_op": "CREATE" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjEwMS4wCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbGdvcmFuZGZvdW5kYXRpb24vVEVBTFNjcmlwdAoKLy8gVGhpcyBjb250cmFjdCBpcyBjb21wbGlhbnQgd2l0aCBhbmQvb3IgaW1wbGVtZW50cyB0aGUgZm9sbG93aW5nIEFSQ3M6IFsgQVJDNCBdCgovLyBUaGUgZm9sbG93aW5nIHRlbiBsaW5lcyBvZiBURUFMIGhhbmRsZSBpbml0aWFsIHByb2dyYW0gZmxvdwovLyBUaGlzIHBhdHRlcm4gaXMgdXNlZCB0byBtYWtlIGl0IGVhc3kgZm9yIGFueW9uZSB0byBwYXJzZSB0aGUgc3RhcnQgb2YgdGhlIHByb2dyYW0gYW5kIGRldGVybWluZSBpZiBhIHNwZWNpZmljIGFjdGlvbiBpcyBhbGxvd2VkCi8vIEhlcmUsIGFjdGlvbiByZWZlcnMgdG8gdGhlIE9uQ29tcGxldGUgaW4gY29tYmluYXRpb24gd2l0aCB3aGV0aGVyIHRoZSBhcHAgaXMgYmVpbmcgY3JlYXRlZCBvciBjYWxsZWQKLy8gRXZlcnkgcG9zc2libGUgYWN0aW9uIGZvciB0aGlzIGNvbnRyYWN0IGlzIHJlcHJlc2VudGVkIGluIHRoZSBzd2l0Y2ggc3RhdGVtZW50Ci8vIElmIHRoZSBhY3Rpb24gaXMgbm90IGltcGxlbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlc3BlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIipOT1RfSU1QTEVNRU5URUQiIHdoaWNoIGp1c3QgY29udGFpbnMgImVyciIKdHhuIEFwcGxpY2F0aW9uSUQKIQppbnQgNgoqCnR4biBPbkNvbXBsZXRpb24KKwpzd2l0Y2ggKmNhbGxfTm9PcCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKmNyZWF0ZV9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRAoKKk5PVF9JTVBMRU1FTlRFRDoKCS8vIFRoZSByZXF1ZXN0ZWQgYWN0aW9uIGlzIG5vdCBpbXBsZW1lbnRlZCBpbiB0aGlzIGNvbnRyYWN0LiBBcmUgeW91IHVzaW5nIHRoZSBjb3JyZWN0IE9uQ29tcGxldGU/IERpZCB5b3Ugc2V0IHlvdXIgYXBwIElEPwoJZXJyCgovLyBjYWxsTm9uQ2xhc3NGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2NhbGxOb25DbGFzc0Z1bmN0aW9uOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBiOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyBhOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGNhbGxOb25DbGFzc0Z1bmN0aW9uCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gY2FsbE5vbkNsYXNzRnVuY3Rpb24oYTogdWludDY0LCBiOiB1aW50NjQpOiB1aW50NjQKY2FsbE5vbkNsYXNzRnVuY3Rpb246Cglwcm90byAyIDEKCgkvLyB0ZXN0cy9jb250cmFjdHMvZnVuY3Rpb25zLmFsZ28udHM6OQoJLy8gcmV0dXJuIG5vbkNsYXNzRnVuY3Rpb24oYSwgYik7CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgljYWxsc3ViIG5vbkNsYXNzRnVuY3Rpb24KCXJldHN1YgoKKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCWludCAxCglyZXR1cm4KCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgoJLy8gdGhpcyBjb250cmFjdCBkb2VzIG5vdCBpbXBsZW1lbnQgdGhlIGdpdmVuIEFCSSBtZXRob2QgZm9yIGNyZWF0ZSBOb09wCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9jYWxsTm9uQ2xhc3NGdW5jdGlvbgoKCS8vIHRoaXMgY29udHJhY3QgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBnaXZlbiBBQkkgbWV0aG9kIGZvciBjYWxsIE5vT3AKCWVycgoKLy8gbm9uQ2xhc3NGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApub25DbGFzc0Z1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy5hbGdvLnRzOjQKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1Yg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "contract": { + "name": "FunctionsTest", + "desc": "", + "methods": [ + { + "name": "callNonClassFunction", + "args": [ + { + "name": "a", + "type": "uint64" + }, + { + "name": "b", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "createApplication", + "args": [], + "returns": { + "type": "void" + } + } + ] + } +} \ No newline at end of file diff --git a/tests/contracts/artifacts/FunctionsTest.arc4.json b/tests/contracts/artifacts/FunctionsTest.arc4.json new file mode 100644 index 000000000..cbfc38dfd --- /dev/null +++ b/tests/contracts/artifacts/FunctionsTest.arc4.json @@ -0,0 +1,29 @@ +{ + "name": "FunctionsTest", + "desc": "", + "methods": [ + { + "name": "callNonClassFunction", + "args": [ + { + "name": "a", + "type": "uint64" + }, + { + "name": "b", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "createApplication", + "args": [], + "returns": { + "type": "void" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/FunctionsTest.arc56_draft.json b/tests/contracts/artifacts/FunctionsTest.arc56_draft.json new file mode 100644 index 000000000..6a9de8a8b --- /dev/null +++ b/tests/contracts/artifacts/FunctionsTest.arc56_draft.json @@ -0,0 +1,446 @@ +{ + "name": "FunctionsTest", + "desc": "", + "methods": [ + { + "name": "callNonClassFunction", + "args": [ + { + "name": "a", + "type": "uint64" + }, + { + "name": "b", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, + { + "name": "createApplication", + "args": [], + "returns": { + "type": "void" + }, + "actions": { + "create": [ + "NoOp" + ], + "call": [] + } + } + ], + "arcs": [ + 4, + 56 + ], + "structs": {}, + "state": { + "schema": { + "global": { + "bytes": 0, + "ints": 0 + }, + "local": { + "bytes": 0, + "ints": 0 + } + }, + "keys": { + "global": {}, + "local": {}, + "box": {} + }, + "maps": { + "global": {}, + "local": {}, + "box": {} + } + }, + "bareActions": { + "create": [], + "call": [] + }, + "sourceInfo": [ + { + "teal": 1, + "source": 7, + "pc": [ + 0, + 1, + 2, + 3 + ] + }, + { + "teal": 13, + "source": 7, + "pc": [ + 4, + 5 + ] + }, + { + "teal": 14, + "source": 7, + "pc": [ + 6 + ] + }, + { + "teal": 15, + "source": 7, + "pc": [ + 7, + 8 + ] + }, + { + "teal": 16, + "source": 7, + "pc": [ + 9 + ] + }, + { + "teal": 17, + "source": 7, + "pc": [ + 10, + 11 + ] + }, + { + "teal": 18, + "source": 7, + "pc": [ + 12 + ] + }, + { + "teal": 19, + "source": 7, + "pc": [ + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38 + ] + }, + { + "teal": 23, + "source": 7, + "errorMessage": "The requested action is not implemented in this contract. Are you using the correct OnComplete? Did you set your app ID?", + "pc": [ + 39 + ] + }, + { + "teal": 28, + "source": 8, + "pc": [ + 40, + 41, + 42, + 43, + 44, + 45 + ] + }, + { + "teal": 31, + "source": 8, + "pc": [ + 46, + 47, + 48 + ] + }, + { + "teal": 32, + "source": 8, + "pc": [ + 49 + ] + }, + { + "teal": 35, + "source": 8, + "pc": [ + 50, + 51, + 52 + ] + }, + { + "teal": 36, + "source": 8, + "pc": [ + 53 + ] + }, + { + "teal": 39, + "source": 8, + "pc": [ + 54, + 55, + 56 + ] + }, + { + "teal": 40, + "source": 8, + "pc": [ + 57 + ] + }, + { + "teal": 41, + "source": 8, + "pc": [ + 58 + ] + }, + { + "teal": 42, + "source": 8, + "pc": [ + 59 + ] + }, + { + "teal": 43, + "source": 8, + "pc": [ + 60 + ] + }, + { + "teal": 44, + "source": 8, + "pc": [ + 61 + ] + }, + { + "teal": 48, + "source": 8, + "pc": [ + 62, + 63, + 64 + ] + }, + { + "teal": 52, + "source": 9, + "pc": [ + 65, + 66 + ] + }, + { + "teal": 53, + "source": 9, + "pc": [ + 67, + 68 + ] + }, + { + "teal": 54, + "source": 9, + "pc": [ + 69, + 70, + 71 + ] + }, + { + "teal": 55, + "source": 8, + "pc": [ + 72 + ] + }, + { + "teal": 58, + "source": 7, + "pc": [ + 73 + ] + }, + { + "teal": 59, + "source": 7, + "pc": [ + 74 + ] + }, + { + "teal": 62, + "source": 7, + "pc": [ + 75, + 76, + 77, + 78, + 79, + 80 + ] + }, + { + "teal": 63, + "source": 7, + "pc": [ + 81, + 82, + 83 + ] + }, + { + "teal": 64, + "source": 7, + "pc": [ + 84, + 85, + 86, + 87 + ] + }, + { + "teal": 67, + "source": 7, + "errorMessage": "this contract does not implement the given ABI method for create NoOp", + "pc": [ + 88 + ] + }, + { + "teal": 70, + "source": 7, + "pc": [ + 89, + 90, + 91, + 92, + 93, + 94 + ] + }, + { + "teal": 71, + "source": 7, + "pc": [ + 95, + 96, + 97 + ] + }, + { + "teal": 72, + "source": 7, + "pc": [ + 98, + 99, + 100, + 101 + ] + }, + { + "teal": 75, + "source": 7, + "errorMessage": "this contract does not implement the given ABI method for call NoOp", + "pc": [ + 102 + ] + }, + { + "teal": 79, + "source": 3, + "pc": [ + 103, + 104, + 105 + ] + }, + { + "teal": 83, + "source": 4, + "pc": [ + 106, + 107 + ] + }, + { + "teal": 84, + "source": 4, + "pc": [ + 108, + 109 + ] + }, + { + "teal": 85, + "source": 4, + "pc": [ + 110 + ] + }, + { + "teal": 86, + "source": 3, + "pc": [ + 111 + ] + } + ], + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjEwMS4wCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbGdvcmFuZGZvdW5kYXRpb24vVEVBTFNjcmlwdAoKLy8gVGhpcyBjb250cmFjdCBpcyBjb21wbGlhbnQgd2l0aCBhbmQvb3IgaW1wbGVtZW50cyB0aGUgZm9sbG93aW5nIEFSQ3M6IFsgQVJDNCBdCgovLyBUaGUgZm9sbG93aW5nIHRlbiBsaW5lcyBvZiBURUFMIGhhbmRsZSBpbml0aWFsIHByb2dyYW0gZmxvdwovLyBUaGlzIHBhdHRlcm4gaXMgdXNlZCB0byBtYWtlIGl0IGVhc3kgZm9yIGFueW9uZSB0byBwYXJzZSB0aGUgc3RhcnQgb2YgdGhlIHByb2dyYW0gYW5kIGRldGVybWluZSBpZiBhIHNwZWNpZmljIGFjdGlvbiBpcyBhbGxvd2VkCi8vIEhlcmUsIGFjdGlvbiByZWZlcnMgdG8gdGhlIE9uQ29tcGxldGUgaW4gY29tYmluYXRpb24gd2l0aCB3aGV0aGVyIHRoZSBhcHAgaXMgYmVpbmcgY3JlYXRlZCBvciBjYWxsZWQKLy8gRXZlcnkgcG9zc2libGUgYWN0aW9uIGZvciB0aGlzIGNvbnRyYWN0IGlzIHJlcHJlc2VudGVkIGluIHRoZSBzd2l0Y2ggc3RhdGVtZW50Ci8vIElmIHRoZSBhY3Rpb24gaXMgbm90IGltcGxlbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlc3BlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIipOT1RfSU1QTEVNRU5URUQiIHdoaWNoIGp1c3QgY29udGFpbnMgImVyciIKdHhuIEFwcGxpY2F0aW9uSUQKIQppbnQgNgoqCnR4biBPbkNvbXBsZXRpb24KKwpzd2l0Y2ggKmNhbGxfTm9PcCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKmNyZWF0ZV9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRAoKKk5PVF9JTVBMRU1FTlRFRDoKCS8vIFRoZSByZXF1ZXN0ZWQgYWN0aW9uIGlzIG5vdCBpbXBsZW1lbnRlZCBpbiB0aGlzIGNvbnRyYWN0LiBBcmUgeW91IHVzaW5nIHRoZSBjb3JyZWN0IE9uQ29tcGxldGU/IERpZCB5b3Ugc2V0IHlvdXIgYXBwIElEPwoJZXJyCgovLyBjYWxsTm9uQ2xhc3NGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2NhbGxOb25DbGFzc0Z1bmN0aW9uOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBiOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyBhOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGNhbGxOb25DbGFzc0Z1bmN0aW9uCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gY2FsbE5vbkNsYXNzRnVuY3Rpb24oYTogdWludDY0LCBiOiB1aW50NjQpOiB1aW50NjQKY2FsbE5vbkNsYXNzRnVuY3Rpb246Cglwcm90byAyIDEKCgkvLyB0ZXN0cy9jb250cmFjdHMvZnVuY3Rpb25zLmFsZ28udHM6OQoJLy8gcmV0dXJuIG5vbkNsYXNzRnVuY3Rpb24oYSwgYik7CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgljYWxsc3ViIG5vbkNsYXNzRnVuY3Rpb24KCXJldHN1YgoKKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCWludCAxCglyZXR1cm4KCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgoJLy8gdGhpcyBjb250cmFjdCBkb2VzIG5vdCBpbXBsZW1lbnQgdGhlIGdpdmVuIEFCSSBtZXRob2QgZm9yIGNyZWF0ZSBOb09wCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9jYWxsTm9uQ2xhc3NGdW5jdGlvbgoKCS8vIHRoaXMgY29udHJhY3QgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBnaXZlbiBBQkkgbWV0aG9kIGZvciBjYWxsIE5vT3AKCWVycgoKLy8gbm9uQ2xhc3NGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApub25DbGFzc0Z1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy5hbGdvLnRzOjQKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1Yg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "byteCode": { + "approval": "CiABATEYFIEGCzEZCI0MADIAAAAAAAAAAAAAACQAAAAAAAAAAAAAAIAEFR98dTYaAhc2GgEXiAAFFlCwIkOKAgGL/ov/iAAfiSJDgAS4RHs2NhoAjgH/8QCABI/SO0g2GgCOAf/CAIoCAYv/i/4IiQ==", + "clear": "Cg==" + }, + "compilerInfo": { + "compiler": "algod", + "compilerVersion": { + "major": 3, + "minor": 25, + "patch": 0, + "commitHash": "9855f57c" + } + } +} \ No newline at end of file diff --git a/tests/contracts/artifacts/FunctionsTest.clear.teal b/tests/contracts/artifacts/FunctionsTest.clear.teal new file mode 100644 index 000000000..e9f1d65b3 --- /dev/null +++ b/tests/contracts/artifacts/FunctionsTest.clear.teal @@ -0,0 +1 @@ +#pragma version 10 \ No newline at end of file diff --git a/tests/contracts/functions.algo.ts b/tests/contracts/functions.algo.ts new file mode 100644 index 000000000..57a062279 --- /dev/null +++ b/tests/contracts/functions.algo.ts @@ -0,0 +1,11 @@ +import { Contract } from '../../src/lib/index'; + +function nonClassFunction(a: uint64, b: uint64): uint64 { + return a + b; +} + +export class FunctionsTest extends Contract { + callNonClassFunction(a: uint64, b: uint64): uint64 { + return nonClassFunction(a, b); + } +} diff --git a/tests/functions.test.ts b/tests/functions.test.ts new file mode 100644 index 000000000..df897fca4 --- /dev/null +++ b/tests/functions.test.ts @@ -0,0 +1,23 @@ +/* eslint-disable func-names */ +/* eslint-disable prefer-arrow-callback */ + +import * as algokit from '@algorandfoundation/algokit-utils'; +import { describe, test, expect } from '@jest/globals'; +import { artifactsTest, compileAndCreate, runMethod, algodClient, kmdClient, getErrorMessage } from './common'; + +const NAME = 'FunctionsTest'; +const PATH = 'tests/contracts/functions.algo.ts'; +const ARTIFACTS_DIR = 'tests/contracts/artifacts/'; + +describe('Functions', function () { + artifactsTest(PATH, ARTIFACTS_DIR, NAME); + + describe('E2E', function () { + const sender = algokit.getLocalNetDispenserAccount(algodClient, kmdClient); + + test('callNonClassFunction', async function () { + const { appClient } = await compileAndCreate(await sender, PATH, ARTIFACTS_DIR, NAME); + expect(await runMethod({ appClient, method: 'callNonClassFunction', methodArgs: [1n, 2n] })).toBe(3n); + }); + }); +}); From 8daa217c80d9f98d4dfb53450d4e03afce711d9d Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sat, 14 Sep 2024 09:02:42 -0400 Subject: [PATCH 2/2] callExternalFunction --- .../artifacts/FunctionsTest.approval.teal | 50 +- .../artifacts/FunctionsTest.arc32.json | 23 +- .../artifacts/FunctionsTest.arc4.json | 16 + .../artifacts/FunctionsTest.arc56_draft.json | 469 +++++++++++++----- tests/contracts/functions-external.algo.ts | 3 + tests/contracts/functions.algo.ts | 5 + tests/functions.test.ts | 2 +- 7 files changed, 429 insertions(+), 139 deletions(-) create mode 100644 tests/contracts/functions-external.algo.ts diff --git a/tests/contracts/artifacts/FunctionsTest.approval.teal b/tests/contracts/artifacts/FunctionsTest.approval.teal index 3b51fcccd..3847f4890 100644 --- a/tests/contracts/artifacts/FunctionsTest.approval.teal +++ b/tests/contracts/artifacts/FunctionsTest.approval.teal @@ -47,13 +47,45 @@ switch *call_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEM callNonClassFunction: proto 2 1 - // tests/contracts/functions.algo.ts:9 + // tests/contracts/functions.algo.ts:10 // return nonClassFunction(a, b); frame_dig -2 // b: uint64 frame_dig -1 // a: uint64 callsub nonClassFunction retsub +// callExternalFunction(uint64,uint64)uint64 +*abi_route_callExternalFunction: + // The ABI return prefix + byte 0x151f7c75 + + // b: uint64 + txna ApplicationArgs 2 + btoi + + // a: uint64 + txna ApplicationArgs 1 + btoi + + // execute callExternalFunction(uint64,uint64)uint64 + callsub callExternalFunction + itob + concat + log + int 1 + return + +// callExternalFunction(a: uint64, b: uint64): uint64 +callExternalFunction: + proto 2 1 + + // tests/contracts/functions.algo.ts:14 + // return externalFunction(a, b); + frame_dig -2 // b: uint64 + frame_dig -1 // a: uint64 + callsub externalFunction + retsub + *abi_route_createApplication: int 1 return @@ -68,17 +100,29 @@ callNonClassFunction: *call_NoOp: method "callNonClassFunction(uint64,uint64)uint64" + method "callExternalFunction(uint64,uint64)uint64" txna ApplicationArgs 0 - match *abi_route_callNonClassFunction + match *abi_route_callNonClassFunction *abi_route_callExternalFunction // this contract does not implement the given ABI method for call NoOp err +// externalFunction(a: uint64, b: uint64): uint64 +externalFunction: + proto 2 1 + + // tests/contracts/functions-external.algo.ts:2 + // return a + b; + frame_dig -1 // a: uint64 + frame_dig -2 // b: uint64 + + + retsub + // nonClassFunction(a: uint64, b: uint64): uint64 nonClassFunction: proto 2 1 - // tests/contracts/functions.algo.ts:4 + // tests/contracts/functions.algo.ts:5 // return a + b; frame_dig -1 // a: uint64 frame_dig -2 // b: uint64 diff --git a/tests/contracts/artifacts/FunctionsTest.arc32.json b/tests/contracts/artifacts/FunctionsTest.arc32.json index 7d7b587dd..f040fded3 100644 --- a/tests/contracts/artifacts/FunctionsTest.arc32.json +++ b/tests/contracts/artifacts/FunctionsTest.arc32.json @@ -5,6 +5,11 @@ "no_op": "CALL" } }, + "callExternalFunction(uint64,uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, "createApplication()void": { "call_config": { "no_op": "CREATE" @@ -39,7 +44,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjEwMS4wCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbGdvcmFuZGZvdW5kYXRpb24vVEVBTFNjcmlwdAoKLy8gVGhpcyBjb250cmFjdCBpcyBjb21wbGlhbnQgd2l0aCBhbmQvb3IgaW1wbGVtZW50cyB0aGUgZm9sbG93aW5nIEFSQ3M6IFsgQVJDNCBdCgovLyBUaGUgZm9sbG93aW5nIHRlbiBsaW5lcyBvZiBURUFMIGhhbmRsZSBpbml0aWFsIHByb2dyYW0gZmxvdwovLyBUaGlzIHBhdHRlcm4gaXMgdXNlZCB0byBtYWtlIGl0IGVhc3kgZm9yIGFueW9uZSB0byBwYXJzZSB0aGUgc3RhcnQgb2YgdGhlIHByb2dyYW0gYW5kIGRldGVybWluZSBpZiBhIHNwZWNpZmljIGFjdGlvbiBpcyBhbGxvd2VkCi8vIEhlcmUsIGFjdGlvbiByZWZlcnMgdG8gdGhlIE9uQ29tcGxldGUgaW4gY29tYmluYXRpb24gd2l0aCB3aGV0aGVyIHRoZSBhcHAgaXMgYmVpbmcgY3JlYXRlZCBvciBjYWxsZWQKLy8gRXZlcnkgcG9zc2libGUgYWN0aW9uIGZvciB0aGlzIGNvbnRyYWN0IGlzIHJlcHJlc2VudGVkIGluIHRoZSBzd2l0Y2ggc3RhdGVtZW50Ci8vIElmIHRoZSBhY3Rpb24gaXMgbm90IGltcGxlbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlc3BlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIipOT1RfSU1QTEVNRU5URUQiIHdoaWNoIGp1c3QgY29udGFpbnMgImVyciIKdHhuIEFwcGxpY2F0aW9uSUQKIQppbnQgNgoqCnR4biBPbkNvbXBsZXRpb24KKwpzd2l0Y2ggKmNhbGxfTm9PcCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKmNyZWF0ZV9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRAoKKk5PVF9JTVBMRU1FTlRFRDoKCS8vIFRoZSByZXF1ZXN0ZWQgYWN0aW9uIGlzIG5vdCBpbXBsZW1lbnRlZCBpbiB0aGlzIGNvbnRyYWN0LiBBcmUgeW91IHVzaW5nIHRoZSBjb3JyZWN0IE9uQ29tcGxldGU/IERpZCB5b3Ugc2V0IHlvdXIgYXBwIElEPwoJZXJyCgovLyBjYWxsTm9uQ2xhc3NGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2NhbGxOb25DbGFzc0Z1bmN0aW9uOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBiOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyBhOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGNhbGxOb25DbGFzc0Z1bmN0aW9uCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gY2FsbE5vbkNsYXNzRnVuY3Rpb24oYTogdWludDY0LCBiOiB1aW50NjQpOiB1aW50NjQKY2FsbE5vbkNsYXNzRnVuY3Rpb246Cglwcm90byAyIDEKCgkvLyB0ZXN0cy9jb250cmFjdHMvZnVuY3Rpb25zLmFsZ28udHM6OQoJLy8gcmV0dXJuIG5vbkNsYXNzRnVuY3Rpb24oYSwgYik7CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgljYWxsc3ViIG5vbkNsYXNzRnVuY3Rpb24KCXJldHN1YgoKKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCWludCAxCglyZXR1cm4KCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgoJLy8gdGhpcyBjb250cmFjdCBkb2VzIG5vdCBpbXBsZW1lbnQgdGhlIGdpdmVuIEFCSSBtZXRob2QgZm9yIGNyZWF0ZSBOb09wCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9jYWxsTm9uQ2xhc3NGdW5jdGlvbgoKCS8vIHRoaXMgY29udHJhY3QgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBnaXZlbiBBQkkgbWV0aG9kIGZvciBjYWxsIE5vT3AKCWVycgoKLy8gbm9uQ2xhc3NGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApub25DbGFzc0Z1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy5hbGdvLnRzOjQKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1Yg==", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjEwMS4wCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbGdvcmFuZGZvdW5kYXRpb24vVEVBTFNjcmlwdAoKLy8gVGhpcyBjb250cmFjdCBpcyBjb21wbGlhbnQgd2l0aCBhbmQvb3IgaW1wbGVtZW50cyB0aGUgZm9sbG93aW5nIEFSQ3M6IFsgQVJDNCBdCgovLyBUaGUgZm9sbG93aW5nIHRlbiBsaW5lcyBvZiBURUFMIGhhbmRsZSBpbml0aWFsIHByb2dyYW0gZmxvdwovLyBUaGlzIHBhdHRlcm4gaXMgdXNlZCB0byBtYWtlIGl0IGVhc3kgZm9yIGFueW9uZSB0byBwYXJzZSB0aGUgc3RhcnQgb2YgdGhlIHByb2dyYW0gYW5kIGRldGVybWluZSBpZiBhIHNwZWNpZmljIGFjdGlvbiBpcyBhbGxvd2VkCi8vIEhlcmUsIGFjdGlvbiByZWZlcnMgdG8gdGhlIE9uQ29tcGxldGUgaW4gY29tYmluYXRpb24gd2l0aCB3aGV0aGVyIHRoZSBhcHAgaXMgYmVpbmcgY3JlYXRlZCBvciBjYWxsZWQKLy8gRXZlcnkgcG9zc2libGUgYWN0aW9uIGZvciB0aGlzIGNvbnRyYWN0IGlzIHJlcHJlc2VudGVkIGluIHRoZSBzd2l0Y2ggc3RhdGVtZW50Ci8vIElmIHRoZSBhY3Rpb24gaXMgbm90IGltcGxlbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlc3BlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIipOT1RfSU1QTEVNRU5URUQiIHdoaWNoIGp1c3QgY29udGFpbnMgImVyciIKdHhuIEFwcGxpY2F0aW9uSUQKIQppbnQgNgoqCnR4biBPbkNvbXBsZXRpb24KKwpzd2l0Y2ggKmNhbGxfTm9PcCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKmNyZWF0ZV9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRAoKKk5PVF9JTVBMRU1FTlRFRDoKCS8vIFRoZSByZXF1ZXN0ZWQgYWN0aW9uIGlzIG5vdCBpbXBsZW1lbnRlZCBpbiB0aGlzIGNvbnRyYWN0LiBBcmUgeW91IHVzaW5nIHRoZSBjb3JyZWN0IE9uQ29tcGxldGU/IERpZCB5b3Ugc2V0IHlvdXIgYXBwIElEPwoJZXJyCgovLyBjYWxsTm9uQ2xhc3NGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2NhbGxOb25DbGFzc0Z1bmN0aW9uOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBiOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyBhOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGNhbGxOb25DbGFzc0Z1bmN0aW9uCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gY2FsbE5vbkNsYXNzRnVuY3Rpb24oYTogdWludDY0LCBiOiB1aW50NjQpOiB1aW50NjQKY2FsbE5vbkNsYXNzRnVuY3Rpb246Cglwcm90byAyIDEKCgkvLyB0ZXN0cy9jb250cmFjdHMvZnVuY3Rpb25zLmFsZ28udHM6MTAKCS8vIHJldHVybiBub25DbGFzc0Z1bmN0aW9uKGEsIGIpOwoJZnJhbWVfZGlnIC0yIC8vIGI6IHVpbnQ2NAoJZnJhbWVfZGlnIC0xIC8vIGE6IHVpbnQ2NAoJY2FsbHN1YiBub25DbGFzc0Z1bmN0aW9uCglyZXRzdWIKCi8vIGNhbGxFeHRlcm5hbEZ1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CiphYmlfcm91dGVfY2FsbEV4dGVybmFsRnVuY3Rpb246CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGI6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIGE6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2FsbEV4dGVybmFsRnVuY3Rpb24odWludDY0LHVpbnQ2NCl1aW50NjQKCWNhbGxzdWIgY2FsbEV4dGVybmFsRnVuY3Rpb24KCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBjYWxsRXh0ZXJuYWxGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApjYWxsRXh0ZXJuYWxGdW5jdGlvbjoKCXByb3RvIDIgMQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9mdW5jdGlvbnMuYWxnby50czoxNAoJLy8gcmV0dXJuIGV4dGVybmFsRnVuY3Rpb24oYSwgYik7CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgljYWxsc3ViIGV4dGVybmFsRnVuY3Rpb24KCXJldHN1YgoKKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCWludCAxCglyZXR1cm4KCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgoJLy8gdGhpcyBjb250cmFjdCBkb2VzIG5vdCBpbXBsZW1lbnQgdGhlIGdpdmVuIEFCSSBtZXRob2QgZm9yIGNyZWF0ZSBOb09wCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJbWV0aG9kICJjYWxsRXh0ZXJuYWxGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoICphYmlfcm91dGVfY2FsbE5vbkNsYXNzRnVuY3Rpb24gKmFiaV9yb3V0ZV9jYWxsRXh0ZXJuYWxGdW5jdGlvbgoKCS8vIHRoaXMgY29udHJhY3QgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBnaXZlbiBBQkkgbWV0aG9kIGZvciBjYWxsIE5vT3AKCWVycgoKLy8gZXh0ZXJuYWxGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApleHRlcm5hbEZ1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy1leHRlcm5hbC5hbGdvLnRzOjIKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1YgoKLy8gbm9uQ2xhc3NGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApub25DbGFzc0Z1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy5hbGdvLnRzOjUKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1Yg==", "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" }, "contract": { @@ -62,6 +67,22 @@ "type": "uint64" } }, + { + "name": "callExternalFunction", + "args": [ + { + "name": "a", + "type": "uint64" + }, + { + "name": "b", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, { "name": "createApplication", "args": [], diff --git a/tests/contracts/artifacts/FunctionsTest.arc4.json b/tests/contracts/artifacts/FunctionsTest.arc4.json index cbfc38dfd..7784d5099 100644 --- a/tests/contracts/artifacts/FunctionsTest.arc4.json +++ b/tests/contracts/artifacts/FunctionsTest.arc4.json @@ -18,6 +18,22 @@ "type": "uint64" } }, + { + "name": "callExternalFunction", + "args": [ + { + "name": "a", + "type": "uint64" + }, + { + "name": "b", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, { "name": "createApplication", "args": [], diff --git a/tests/contracts/artifacts/FunctionsTest.arc56_draft.json b/tests/contracts/artifacts/FunctionsTest.arc56_draft.json index 6a9de8a8b..2c455d868 100644 --- a/tests/contracts/artifacts/FunctionsTest.arc56_draft.json +++ b/tests/contracts/artifacts/FunctionsTest.arc56_draft.json @@ -24,6 +24,28 @@ ] } }, + { + "name": "callExternalFunction", + "args": [ + { + "name": "a", + "type": "uint64" + }, + { + "name": "b", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + } + }, { "name": "createApplication", "args": [], @@ -72,70 +94,70 @@ "sourceInfo": [ { "teal": 1, - "source": 7, + "source": 8, "pc": [ 0, 1, 2, - 3 + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 ] }, { "teal": 13, - "source": 7, + "source": 8, "pc": [ - 4, - 5 + 11, + 12 ] }, { "teal": 14, - "source": 7, + "source": 8, "pc": [ - 6 + 13 ] }, { "teal": 15, - "source": 7, + "source": 8, "pc": [ - 7, - 8 + 14, + 15 ] }, { "teal": 16, - "source": 7, + "source": 8, "pc": [ - 9 + 16 ] }, { "teal": 17, - "source": 7, + "source": 8, "pc": [ - 10, - 11 + 17, + 18 ] }, { "teal": 18, - "source": 7, + "source": 8, "pc": [ - 12 + 19 ] }, { "teal": 19, - "source": 7, + "source": 8, "pc": [ - 13, - 14, - 15, - 16, - 17, - 18, - 19, 20, 21, 22, @@ -154,284 +176,463 @@ 35, 36, 37, - 38 + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45 ] }, { "teal": 23, - "source": 7, + "source": 8, "errorMessage": "The requested action is not implemented in this contract. Are you using the correct OnComplete? Did you set your app ID?", "pc": [ - 39 + 46 ] }, { "teal": 28, - "source": 8, + "source": 9, "pc": [ - 40, - 41, - 42, - 43, - 44, - 45 + 47 ] }, { "teal": 31, - "source": 8, + "source": 9, "pc": [ - 46, - 47, - 48 + 48, + 49, + 50 ] }, { "teal": 32, - "source": 8, + "source": 9, "pc": [ - 49 + 51 ] }, { "teal": 35, - "source": 8, + "source": 9, "pc": [ - 50, - 51, - 52 + 52, + 53, + 54 ] }, { "teal": 36, - "source": 8, + "source": 9, "pc": [ - 53 + 55 ] }, { "teal": 39, - "source": 8, + "source": 9, "pc": [ - 54, - 55, - 56 + 56, + 57, + 58 ] }, { "teal": 40, - "source": 8, + "source": 9, "pc": [ - 57 + 59 ] }, { "teal": 41, - "source": 8, + "source": 9, "pc": [ - 58 + 60 ] }, { "teal": 42, - "source": 8, + "source": 9, "pc": [ - 59 + 61 ] }, { "teal": 43, - "source": 8, + "source": 9, "pc": [ - 60 + 62 ] }, { "teal": 44, - "source": 8, + "source": 9, "pc": [ - 61 + 63 ] }, { "teal": 48, - "source": 8, - "pc": [ - 62, - 63, - 64 - ] - }, - { - "teal": 52, "source": 9, "pc": [ + 64, 65, 66 ] }, { - "teal": 53, - "source": 9, + "teal": 52, + "source": 10, "pc": [ 67, 68 ] }, { - "teal": 54, - "source": 9, + "teal": 53, + "source": 10, "pc": [ 69, - 70, - 71 + 70 ] }, { - "teal": 55, - "source": 8, + "teal": 54, + "source": 10, "pc": [ - 72 + 71, + 72, + 73 ] }, { - "teal": 58, - "source": 7, + "teal": 55, + "source": 9, "pc": [ - 73 + 74 ] }, { - "teal": 59, - "source": 7, + "teal": 60, + "source": 13, "pc": [ - 74 + 75 ] }, { - "teal": 62, - "source": 7, + "teal": 63, + "source": 13, "pc": [ - 75, 76, 77, - 78, - 79, - 80 + 78 ] }, { - "teal": 63, - "source": 7, + "teal": 64, + "source": 13, + "pc": [ + 79 + ] + }, + { + "teal": 67, + "source": 13, "pc": [ + 80, 81, - 82, + 82 + ] + }, + { + "teal": 68, + "source": 13, + "pc": [ 83 ] }, { - "teal": 64, - "source": 7, + "teal": 71, + "source": 13, "pc": [ 84, 85, - 86, + 86 + ] + }, + { + "teal": 72, + "source": 13, + "pc": [ 87 ] }, { - "teal": 67, - "source": 7, - "errorMessage": "this contract does not implement the given ABI method for create NoOp", + "teal": 73, + "source": 13, "pc": [ 88 ] }, { - "teal": 70, - "source": 7, + "teal": 74, + "source": 13, + "pc": [ + 89 + ] + }, + { + "teal": 75, + "source": 13, + "pc": [ + 90 + ] + }, + { + "teal": 76, + "source": 13, + "pc": [ + 91 + ] + }, + { + "teal": 80, + "source": 13, "pc": [ - 89, - 90, - 91, 92, 93, 94 ] }, { - "teal": 71, - "source": 7, + "teal": 84, + "source": 14, "pc": [ 95, - 96, - 97 + 96 ] }, { - "teal": 72, - "source": 7, + "teal": 85, + "source": 14, + "pc": [ + 97, + 98 + ] + }, + { + "teal": 86, + "source": 14, "pc": [ - 98, 99, 100, 101 ] }, { - "teal": 75, - "source": 7, - "errorMessage": "this contract does not implement the given ABI method for call NoOp", + "teal": 87, + "source": 13, "pc": [ 102 ] }, { - "teal": 79, - "source": 3, + "teal": 90, + "source": 8, "pc": [ - 103, - 104, - 105 + 103 ] }, { - "teal": 83, - "source": 4, + "teal": 91, + "source": 8, "pc": [ - 106, - 107 + 104 ] }, { - "teal": 84, - "source": 4, + "teal": 94, + "source": 8, "pc": [ + 105, + 106, + 107, 108, - 109 + 109, + 110 ] }, { - "teal": 85, + "teal": 95, + "source": 8, + "pc": [ + 111, + 112, + 113 + ] + }, + { + "teal": 96, + "source": 8, + "pc": [ + 114, + 115, + 116, + 117 + ] + }, + { + "teal": 99, + "source": 8, + "errorMessage": "this contract does not implement the given ABI method for create NoOp", + "pc": [ + 118 + ] + }, + { + "teal": 102, + "source": 8, + "pc": [ + 119, + 120, + 121, + 122, + 123, + 124 + ] + }, + { + "teal": 103, + "source": 8, + "pc": [ + 125, + 126, + 127, + 128, + 129, + 130 + ] + }, + { + "teal": 104, + "source": 8, + "pc": [ + 131, + 132, + 133 + ] + }, + { + "teal": 105, + "source": 8, + "pc": [ + 134, + 135, + 136, + 137, + 138, + 139 + ] + }, + { + "teal": 108, + "source": 8, + "errorMessage": "this contract does not implement the given ABI method for call NoOp", + "pc": [ + 140 + ] + }, + { + "teal": 112, + "source": 1, + "pc": [ + 141, + 142, + 143 + ] + }, + { + "teal": 116, + "source": 2, + "pc": [ + 144, + 145 + ] + }, + { + "teal": 117, + "source": 2, + "pc": [ + 146, + 147 + ] + }, + { + "teal": 118, + "source": 2, + "pc": [ + 148 + ] + }, + { + "teal": 119, + "source": 1, + "pc": [ + 149 + ] + }, + { + "teal": 123, "source": 4, "pc": [ - 110 + 150, + 151, + 152 ] }, { - "teal": 86, - "source": 3, + "teal": 127, + "source": 5, + "pc": [ + 153, + 154 + ] + }, + { + "teal": 128, + "source": 5, + "pc": [ + 155, + 156 + ] + }, + { + "teal": 129, + "source": 5, + "pc": [ + 157 + ] + }, + { + "teal": 130, + "source": 4, "pc": [ - 111 + 158 ] } ], "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjEwMS4wCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbGdvcmFuZGZvdW5kYXRpb24vVEVBTFNjcmlwdAoKLy8gVGhpcyBjb250cmFjdCBpcyBjb21wbGlhbnQgd2l0aCBhbmQvb3IgaW1wbGVtZW50cyB0aGUgZm9sbG93aW5nIEFSQ3M6IFsgQVJDNCBdCgovLyBUaGUgZm9sbG93aW5nIHRlbiBsaW5lcyBvZiBURUFMIGhhbmRsZSBpbml0aWFsIHByb2dyYW0gZmxvdwovLyBUaGlzIHBhdHRlcm4gaXMgdXNlZCB0byBtYWtlIGl0IGVhc3kgZm9yIGFueW9uZSB0byBwYXJzZSB0aGUgc3RhcnQgb2YgdGhlIHByb2dyYW0gYW5kIGRldGVybWluZSBpZiBhIHNwZWNpZmljIGFjdGlvbiBpcyBhbGxvd2VkCi8vIEhlcmUsIGFjdGlvbiByZWZlcnMgdG8gdGhlIE9uQ29tcGxldGUgaW4gY29tYmluYXRpb24gd2l0aCB3aGV0aGVyIHRoZSBhcHAgaXMgYmVpbmcgY3JlYXRlZCBvciBjYWxsZWQKLy8gRXZlcnkgcG9zc2libGUgYWN0aW9uIGZvciB0aGlzIGNvbnRyYWN0IGlzIHJlcHJlc2VudGVkIGluIHRoZSBzd2l0Y2ggc3RhdGVtZW50Ci8vIElmIHRoZSBhY3Rpb24gaXMgbm90IGltcGxlbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlc3BlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIipOT1RfSU1QTEVNRU5URUQiIHdoaWNoIGp1c3QgY29udGFpbnMgImVyciIKdHhuIEFwcGxpY2F0aW9uSUQKIQppbnQgNgoqCnR4biBPbkNvbXBsZXRpb24KKwpzd2l0Y2ggKmNhbGxfTm9PcCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKmNyZWF0ZV9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRAoKKk5PVF9JTVBMRU1FTlRFRDoKCS8vIFRoZSByZXF1ZXN0ZWQgYWN0aW9uIGlzIG5vdCBpbXBsZW1lbnRlZCBpbiB0aGlzIGNvbnRyYWN0LiBBcmUgeW91IHVzaW5nIHRoZSBjb3JyZWN0IE9uQ29tcGxldGU/IERpZCB5b3Ugc2V0IHlvdXIgYXBwIElEPwoJZXJyCgovLyBjYWxsTm9uQ2xhc3NGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2NhbGxOb25DbGFzc0Z1bmN0aW9uOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBiOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyBhOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGNhbGxOb25DbGFzc0Z1bmN0aW9uCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gY2FsbE5vbkNsYXNzRnVuY3Rpb24oYTogdWludDY0LCBiOiB1aW50NjQpOiB1aW50NjQKY2FsbE5vbkNsYXNzRnVuY3Rpb246Cglwcm90byAyIDEKCgkvLyB0ZXN0cy9jb250cmFjdHMvZnVuY3Rpb25zLmFsZ28udHM6OQoJLy8gcmV0dXJuIG5vbkNsYXNzRnVuY3Rpb24oYSwgYik7CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgljYWxsc3ViIG5vbkNsYXNzRnVuY3Rpb24KCXJldHN1YgoKKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCWludCAxCglyZXR1cm4KCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgoJLy8gdGhpcyBjb250cmFjdCBkb2VzIG5vdCBpbXBsZW1lbnQgdGhlIGdpdmVuIEFCSSBtZXRob2QgZm9yIGNyZWF0ZSBOb09wCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9jYWxsTm9uQ2xhc3NGdW5jdGlvbgoKCS8vIHRoaXMgY29udHJhY3QgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBnaXZlbiBBQkkgbWV0aG9kIGZvciBjYWxsIE5vT3AKCWVycgoKLy8gbm9uQ2xhc3NGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApub25DbGFzc0Z1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy5hbGdvLnRzOjQKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1Yg==", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjEwMS4wCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbGdvcmFuZGZvdW5kYXRpb24vVEVBTFNjcmlwdAoKLy8gVGhpcyBjb250cmFjdCBpcyBjb21wbGlhbnQgd2l0aCBhbmQvb3IgaW1wbGVtZW50cyB0aGUgZm9sbG93aW5nIEFSQ3M6IFsgQVJDNCBdCgovLyBUaGUgZm9sbG93aW5nIHRlbiBsaW5lcyBvZiBURUFMIGhhbmRsZSBpbml0aWFsIHByb2dyYW0gZmxvdwovLyBUaGlzIHBhdHRlcm4gaXMgdXNlZCB0byBtYWtlIGl0IGVhc3kgZm9yIGFueW9uZSB0byBwYXJzZSB0aGUgc3RhcnQgb2YgdGhlIHByb2dyYW0gYW5kIGRldGVybWluZSBpZiBhIHNwZWNpZmljIGFjdGlvbiBpcyBhbGxvd2VkCi8vIEhlcmUsIGFjdGlvbiByZWZlcnMgdG8gdGhlIE9uQ29tcGxldGUgaW4gY29tYmluYXRpb24gd2l0aCB3aGV0aGVyIHRoZSBhcHAgaXMgYmVpbmcgY3JlYXRlZCBvciBjYWxsZWQKLy8gRXZlcnkgcG9zc2libGUgYWN0aW9uIGZvciB0aGlzIGNvbnRyYWN0IGlzIHJlcHJlc2VudGVkIGluIHRoZSBzd2l0Y2ggc3RhdGVtZW50Ci8vIElmIHRoZSBhY3Rpb24gaXMgbm90IGltcGxlbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlc3BlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIipOT1RfSU1QTEVNRU5URUQiIHdoaWNoIGp1c3QgY29udGFpbnMgImVyciIKdHhuIEFwcGxpY2F0aW9uSUQKIQppbnQgNgoqCnR4biBPbkNvbXBsZXRpb24KKwpzd2l0Y2ggKmNhbGxfTm9PcCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKmNyZWF0ZV9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRAoKKk5PVF9JTVBMRU1FTlRFRDoKCS8vIFRoZSByZXF1ZXN0ZWQgYWN0aW9uIGlzIG5vdCBpbXBsZW1lbnRlZCBpbiB0aGlzIGNvbnRyYWN0LiBBcmUgeW91IHVzaW5nIHRoZSBjb3JyZWN0IE9uQ29tcGxldGU/IERpZCB5b3Ugc2V0IHlvdXIgYXBwIElEPwoJZXJyCgovLyBjYWxsTm9uQ2xhc3NGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2NhbGxOb25DbGFzc0Z1bmN0aW9uOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBiOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyBhOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGNhbGxOb25DbGFzc0Z1bmN0aW9uCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gY2FsbE5vbkNsYXNzRnVuY3Rpb24oYTogdWludDY0LCBiOiB1aW50NjQpOiB1aW50NjQKY2FsbE5vbkNsYXNzRnVuY3Rpb246Cglwcm90byAyIDEKCgkvLyB0ZXN0cy9jb250cmFjdHMvZnVuY3Rpb25zLmFsZ28udHM6MTAKCS8vIHJldHVybiBub25DbGFzc0Z1bmN0aW9uKGEsIGIpOwoJZnJhbWVfZGlnIC0yIC8vIGI6IHVpbnQ2NAoJZnJhbWVfZGlnIC0xIC8vIGE6IHVpbnQ2NAoJY2FsbHN1YiBub25DbGFzc0Z1bmN0aW9uCglyZXRzdWIKCi8vIGNhbGxFeHRlcm5hbEZ1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0CiphYmlfcm91dGVfY2FsbEV4dGVybmFsRnVuY3Rpb246CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGI6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIGE6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2FsbEV4dGVybmFsRnVuY3Rpb24odWludDY0LHVpbnQ2NCl1aW50NjQKCWNhbGxzdWIgY2FsbEV4dGVybmFsRnVuY3Rpb24KCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBjYWxsRXh0ZXJuYWxGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApjYWxsRXh0ZXJuYWxGdW5jdGlvbjoKCXByb3RvIDIgMQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9mdW5jdGlvbnMuYWxnby50czoxNAoJLy8gcmV0dXJuIGV4dGVybmFsRnVuY3Rpb24oYSwgYik7CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgljYWxsc3ViIGV4dGVybmFsRnVuY3Rpb24KCXJldHN1YgoKKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCWludCAxCglyZXR1cm4KCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgoJLy8gdGhpcyBjb250cmFjdCBkb2VzIG5vdCBpbXBsZW1lbnQgdGhlIGdpdmVuIEFCSSBtZXRob2QgZm9yIGNyZWF0ZSBOb09wCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImNhbGxOb25DbGFzc0Z1bmN0aW9uKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJbWV0aG9kICJjYWxsRXh0ZXJuYWxGdW5jdGlvbih1aW50NjQsdWludDY0KXVpbnQ2NCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoICphYmlfcm91dGVfY2FsbE5vbkNsYXNzRnVuY3Rpb24gKmFiaV9yb3V0ZV9jYWxsRXh0ZXJuYWxGdW5jdGlvbgoKCS8vIHRoaXMgY29udHJhY3QgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBnaXZlbiBBQkkgbWV0aG9kIGZvciBjYWxsIE5vT3AKCWVycgoKLy8gZXh0ZXJuYWxGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApleHRlcm5hbEZ1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy1leHRlcm5hbC5hbGdvLnRzOjIKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1YgoKLy8gbm9uQ2xhc3NGdW5jdGlvbihhOiB1aW50NjQsIGI6IHVpbnQ2NCk6IHVpbnQ2NApub25DbGFzc0Z1bmN0aW9uOgoJcHJvdG8gMiAxCgoJLy8gdGVzdHMvY29udHJhY3RzL2Z1bmN0aW9ucy5hbGdvLnRzOjUKCS8vIHJldHVybiBhICsgYjsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCSsKCXJldHN1Yg==", "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" }, "byteCode": { - "approval": "CiABATEYFIEGCzEZCI0MADIAAAAAAAAAAAAAACQAAAAAAAAAAAAAAIAEFR98dTYaAhc2GgEXiAAFFlCwIkOKAgGL/ov/iAAfiSJDgAS4RHs2NhoAjgH/8QCABI/SO0g2GgCOAf/CAIoCAYv/i/4IiQ==", + "approval": "CiABASYBBBUffHUxGBSBBgsxGQiNDABJAAAAAAAAAAAAAAA7AAAAAAAAAAAAAAAoNhoCFzYaAReIAAUWULAiQ4oCAYv+i/+IAEyJKDYaAhc2GgEXiAAFFlCwIkOKAgGL/ov/iAAniSJDgAS4RHs2NhoAjgH/8QCABI/SO0iABPXbO0E2GgCOAv+j/78AigIBi/+L/giJigIBi/+L/giJ", "clear": "Cg==" }, "compilerInfo": { diff --git a/tests/contracts/functions-external.algo.ts b/tests/contracts/functions-external.algo.ts new file mode 100644 index 000000000..c40ed00a1 --- /dev/null +++ b/tests/contracts/functions-external.algo.ts @@ -0,0 +1,3 @@ +export function externalFunction(a: uint64, b: uint64): uint64 { + return a + b; +} diff --git a/tests/contracts/functions.algo.ts b/tests/contracts/functions.algo.ts index 57a062279..1d04ac077 100644 --- a/tests/contracts/functions.algo.ts +++ b/tests/contracts/functions.algo.ts @@ -1,4 +1,5 @@ import { Contract } from '../../src/lib/index'; +import { externalFunction } from './functions-external.algo'; function nonClassFunction(a: uint64, b: uint64): uint64 { return a + b; @@ -8,4 +9,8 @@ export class FunctionsTest extends Contract { callNonClassFunction(a: uint64, b: uint64): uint64 { return nonClassFunction(a, b); } + + callExternalFunction(a: uint64, b: uint64): uint64 { + return externalFunction(a, b); + } } diff --git a/tests/functions.test.ts b/tests/functions.test.ts index df897fca4..b33a3aff0 100644 --- a/tests/functions.test.ts +++ b/tests/functions.test.ts @@ -3,7 +3,7 @@ import * as algokit from '@algorandfoundation/algokit-utils'; import { describe, test, expect } from '@jest/globals'; -import { artifactsTest, compileAndCreate, runMethod, algodClient, kmdClient, getErrorMessage } from './common'; +import { artifactsTest, compileAndCreate, runMethod, algodClient, kmdClient } from './common'; const NAME = 'FunctionsTest'; const PATH = 'tests/contracts/functions.algo.ts';