diff --git a/README.md b/README.md index b2da66d82..0542d7e37 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,29 @@ TEALScript is still very much a work in progress. The current version is `0.x.x` * ABI ufixed encoding/decoding * More testing * More documentation + +## Example Contract + +The artifacts for this contract can be seen in [examples/calculator/artifacts](./examples/calculator/artifacts) + +```ts +import { Contract } from '../../src/lib/index'; + +class Calculator extends Contract { + private getSum(a: number, b: number): number { + return a + b; + } + + private getDifference(a: number, b: number): number { + return a >= b ? a - b : b - a; + } + + doMath(a: number, b: number, operation: string): number { + if (operation === 'sum') { + return this.getSum(a, b); + } if (operation === 'difference') { + return this.getDifference(a, b); + } throw Error('Invalid operation'); + } +} +``` diff --git a/examples/calculator/artifacts/Calculator.abi.json b/examples/calculator/artifacts/Calculator.abi.json new file mode 100644 index 000000000..bb150c5cd --- /dev/null +++ b/examples/calculator/artifacts/Calculator.abi.json @@ -0,0 +1,31 @@ +{ + "name": "Calculator", + "desc": "", + "methods": [ + { + "name": "doMath", + "args": [ + { + "name": "a", + "type": "uint64", + "desc": "" + }, + { + "name": "b", + "type": "uint64", + "desc": "" + }, + { + "name": "operation", + "type": "string", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "uint64", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/examples/calculator/artifacts/Calculator.approval.teal b/examples/calculator/artifacts/Calculator.approval.teal new file mode 100644 index 000000000..0e3b8a0e5 --- /dev/null +++ b/examples/calculator/artifacts/Calculator.approval.teal @@ -0,0 +1,126 @@ +#pragma version 8 + b main + +getSum: + proto 3 1 + + // examples/calculator/calculator.algo.ts:6 + // return a + b; + frame_dig -1 // a: uint64 + frame_dig -2 // b: uint64 + + + itob + byte 0x151f7c75 + swap + concat + log + retsub + +getDifference: + proto 3 1 + + // examples/calculator/calculator.algo.ts:10 + // return a >= b ? a - b : b - a; + frame_dig -1 // a: uint64 + frame_dig -2 // b: uint64 + >= + bz ternary0_false + frame_dig -1 // a: uint64 + frame_dig -2 // b: uint64 + - + b ternary0_end + +ternary0_false: + frame_dig -2 // b: uint64 + frame_dig -1 // a: uint64 + - + +ternary0_end: + itob + byte 0x151f7c75 + swap + concat + log + retsub + +abi_route_doMath: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + dupn 1 + txna ApplicationArgs 3 + extract 2 0 + txna ApplicationArgs 2 + btoi + txna ApplicationArgs 1 + btoi + callsub doMath + int 1 + return + +doMath: + proto 4 0 + + // if0_condition + // examples/calculator/calculator.algo.ts:14 + // operation === 'sum' + frame_dig -3 // operation: bytes + byte "sum" + == + bz if0_end + + // if0_consequent + // examples/calculator/calculator.algo.ts:15 + // return this.getSum(a, b); + byte 0x + dupn 1 + frame_dig -2 // b: uint64 + frame_dig -1 // a: uint64 + callsub getSum + itob + byte 0x151f7c75 + swap + concat + log + +if0_end: + // if1_condition + // examples/calculator/calculator.algo.ts:16 + // operation === 'difference' + frame_dig -3 // operation: bytes + byte "difference" + == + bz if1_end + + // if1_consequent + // examples/calculator/calculator.algo.ts:17 + // return this.getDifference(a, b); + byte 0x + dupn 1 + frame_dig -2 // b: uint64 + frame_dig -1 // a: uint64 + callsub getDifference + itob + byte 0x151f7c75 + swap + concat + log + +if1_end: + err // 'Invalid operation' + retsub + +main: + txn NumAppArgs + bnz route_abi + +route_abi: + method "doMath(uint64,uint64,string)uint64" + txna ApplicationArgs 0 + match abi_route_doMath \ No newline at end of file diff --git a/examples/calculator/artifacts/Calculator.clear.teal b/examples/calculator/artifacts/Calculator.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/examples/calculator/artifacts/Calculator.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/examples/calculator/artifacts/Calculator.json b/examples/calculator/artifacts/Calculator.json new file mode 100644 index 000000000..d606fbe6c --- /dev/null +++ b/examples/calculator/artifacts/Calculator.json @@ -0,0 +1 @@ +{"hints":{},"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":"I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKZ2V0U3VtOgoJcHJvdG8gMyAxCgoJLy8gZXhhbXBsZXMvY2FsY3VsYXRvci9jYWxjdWxhdG9yLmFsZ28udHM6NgoJLy8gcmV0dXJuIGEgKyBiOwoJZnJhbWVfZGlnIC0xIC8vIGE6IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIGI6IHVpbnQ2NAoJKwoJaXRvYgoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgpnZXREaWZmZXJlbmNlOgoJcHJvdG8gMyAxCgoJLy8gZXhhbXBsZXMvY2FsY3VsYXRvci9jYWxjdWxhdG9yLmFsZ28udHM6MTAKCS8vIHJldHVybiBhID49IGIgPyBhIC0gYiA6IGIgLSBhOwoJZnJhbWVfZGlnIC0xIC8vIGE6IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIGI6IHVpbnQ2NAoJPj0KCWJ6IHRlcm5hcnkwX2ZhbHNlCglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CgktCgliIHRlcm5hcnkwX2VuZAoKdGVybmFyeTBfZmFsc2U6CglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgktCgp0ZXJuYXJ5MF9lbmQ6CglpdG9iCglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCmFiaV9yb3V0ZV9kb01hdGg6Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCWJ5dGUgMHgKCWR1cG4gMQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMwoJZXh0cmFjdCAyIDAKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCWNhbGxzdWIgZG9NYXRoCglpbnQgMQoJcmV0dXJuCgpkb01hdGg6Cglwcm90byA0IDAKCgkvLyBpZjBfY29uZGl0aW9uCgkvLyBleGFtcGxlcy9jYWxjdWxhdG9yL2NhbGN1bGF0b3IuYWxnby50czoxNAoJLy8gb3BlcmF0aW9uID09PSAnc3VtJwoJZnJhbWVfZGlnIC0zIC8vIG9wZXJhdGlvbjogYnl0ZXMKCWJ5dGUgInN1bSIKCT09CglieiBpZjBfZW5kCgoJLy8gaWYwX2NvbnNlcXVlbnQKCS8vIGV4YW1wbGVzL2NhbGN1bGF0b3IvY2FsY3VsYXRvci5hbGdvLnRzOjE1CgkvLyByZXR1cm4gdGhpcy5nZXRTdW0oYSwgYik7CglieXRlIDB4CglkdXBuIDEKCWZyYW1lX2RpZyAtMiAvLyBiOiB1aW50NjQKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50NjQKCWNhbGxzdWIgZ2V0U3VtCglpdG9iCglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCgppZjBfZW5kOgoJLy8gaWYxX2NvbmRpdGlvbgoJLy8gZXhhbXBsZXMvY2FsY3VsYXRvci9jYWxjdWxhdG9yLmFsZ28udHM6MTYKCS8vIG9wZXJhdGlvbiA9PT0gJ2RpZmZlcmVuY2UnCglmcmFtZV9kaWcgLTMgLy8gb3BlcmF0aW9uOiBieXRlcwoJYnl0ZSAiZGlmZmVyZW5jZSIKCT09CglieiBpZjFfZW5kCgoJLy8gaWYxX2NvbnNlcXVlbnQKCS8vIGV4YW1wbGVzL2NhbGN1bGF0b3IvY2FsY3VsYXRvci5hbGdvLnRzOjE3CgkvLyByZXR1cm4gdGhpcy5nZXREaWZmZXJlbmNlKGEsIGIpOwoJYnl0ZSAweAoJZHVwbiAxCglmcmFtZV9kaWcgLTIgLy8gYjogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gYTogdWludDY0CgljYWxsc3ViIGdldERpZmZlcmVuY2UKCWl0b2IKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCmlmMV9lbmQ6CgllcnIgLy8gJ0ludmFsaWQgb3BlcmF0aW9uJwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCnJvdXRlX2FiaToKCW1ldGhvZCAiZG9NYXRoKHVpbnQ2NCx1aW50NjQsc3RyaW5nKXVpbnQ2NCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9kb01hdGg=","clear":"I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu"},"contract":{"name":"Calculator","desc":"","methods":[{"name":"doMath","args":[{"name":"a","type":"uint64","desc":""},{"name":"b","type":"uint64","desc":""},{"name":"operation","type":"string","desc":""}],"desc":"","returns":{"type":"uint64","desc":""}}]}} \ No newline at end of file diff --git a/examples/calculator/artifacts/Calculator.src_map.json b/examples/calculator/artifacts/Calculator.src_map.json new file mode 100644 index 000000000..ef1266fd2 --- /dev/null +++ b/examples/calculator/artifacts/Calculator.src_map.json @@ -0,0 +1,173 @@ +{ + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "7": 0, + "8": 0, + "9": 0, + "10": 0, + "11": 0, + "12": 1, + "13": 1, + "14": 1, + "15": 4, + "16": 4, + "17": 4, + "18": 8, + "19": 8, + "20": 9, + "21": 9, + "22": 10, + "23": 11, + "24": 12, + "25": 13, + "26": 14, + "27": 15, + "28": 16, + "29": 19, + "30": 19, + "31": 19, + "32": 23, + "33": 23, + "34": 24, + "35": 24, + "36": 25, + "37": 26, + "38": 26, + "39": 26, + "40": 27, + "41": 27, + "42": 28, + "43": 28, + "44": 29, + "45": 30, + "46": 30, + "47": 30, + "48": 33, + "49": 33, + "50": 34, + "51": 34, + "52": 35, + "53": 38, + "54": 39, + "55": 40, + "56": 41, + "57": 42, + "58": 43, + "59": 46, + "60": 46, + "61": 47, + "62": 48, + "63": 49, + "64": 49, + "65": 50, + "66": 51, + "67": 52, + "68": 53, + "69": 54, + "70": 55, + "71": 55, + "72": 56, + "73": 56, + "74": 56, + "75": 57, + "76": 57, + "77": 57, + "78": 58, + "79": 58, + "80": 58, + "81": 59, + "82": 60, + "83": 60, + "84": 60, + "85": 61, + "86": 62, + "87": 62, + "88": 62, + "89": 63, + "90": 63, + "91": 64, + "92": 67, + "93": 67, + "94": 67, + "95": 72, + "96": 72, + "97": 73, + "98": 73, + "99": 73, + "100": 73, + "101": 73, + "102": 74, + "103": 75, + "104": 75, + "105": 75, + "106": 80, + "107": 81, + "108": 81, + "109": 82, + "110": 82, + "111": 83, + "112": 83, + "113": 84, + "114": 84, + "115": 84, + "116": 85, + "117": 86, + "118": 87, + "119": 88, + "120": 89, + "121": 95, + "122": 95, + "123": 96, + "124": 96, + "125": 96, + "126": 96, + "127": 96, + "128": 96, + "129": 96, + "130": 96, + "131": 96, + "132": 96, + "133": 96, + "134": 96, + "135": 97, + "136": 98, + "137": 98, + "138": 98, + "139": 103, + "140": 104, + "141": 104, + "142": 105, + "143": 105, + "144": 106, + "145": 106, + "146": 107, + "147": 107, + "148": 107, + "149": 108, + "150": 109, + "151": 110, + "152": 111, + "153": 112, + "154": 115, + "155": 116, + "156": 119, + "157": 119, + "158": 120, + "159": 120, + "160": 120, + "161": 123, + "162": 123, + "163": 123, + "164": 123, + "165": 123, + "166": 123, + "167": 124, + "168": 124, + "169": 124, + "170": 125 +} \ No newline at end of file diff --git a/examples/calculator/calculator.algo.ts b/examples/calculator/calculator.algo.ts new file mode 100644 index 000000000..4c1a1daae --- /dev/null +++ b/examples/calculator/calculator.algo.ts @@ -0,0 +1,20 @@ +import { Contract } from '../../src/lib/index'; + +// eslint-disable-next-line no-unused-vars +class Calculator extends Contract { + private getSum(a: number, b: number): number { + return a + b; + } + + private getDifference(a: number, b: number): number { + return a >= b ? a - b : b - a; + } + + doMath(a: number, b: number, operation: string): number { + if (operation === 'sum') { + return this.getSum(a, b); + } if (operation === 'difference') { + return this.getDifference(a, b); + } throw Error('Invalid operation'); + } +} diff --git a/examples/calculator/tsconfig.json b/examples/calculator/tsconfig.json new file mode 100644 index 000000000..5e3106d17 --- /dev/null +++ b/examples/calculator/tsconfig.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/package.json b/package.json index cf40b6217..4bf4826dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@algorandfoundation/tealscript", - "version": "0.8.2", + "version": "0.9.0", "description": "Enables Algorand smart contract development with native TypeScript syntax, tooling, and IDE support", "homepage": "https://github.com/algorand-devrel/TEALScript", "bugs": { @@ -33,9 +33,10 @@ "compile-itxns": "tsx ./src/bin/tealscript.ts examples/itxns/itxns.algo.ts examples/itxns/artifacts && beaker generate examples/itxns/artifacts/FactoryCaller.json examples/itxns/beaker-client && tsx examples/itxns/demo.ts", "compile-simple": "tsx ./src/bin/tealscript.ts examples/simple/simple.algo.ts examples/simple/artifacts", "compile-tuple_in_box": "tsx ./src/bin/tealscript.ts examples/tuple_in_box/app.algo.ts examples/tuple_in_box/tealscript_artifacts", + "compile-calculator": "tsx ./src/bin/tealscript.ts examples/calculator/calculator.algo.ts examples/calculator/artifacts", "run-tuple_in_box": "yarn compile-tuple_in_box && beaker generate ./examples/tuple_in_box/tealscript_artifacts/ContactsApp.json ./examples/tuple_in_box/tealscript_artifacts && tsx ./examples/tuple_in_box/client.ts", "test-arc75": "yarn compile-arc75 && beaker generate examples/arc75/artifacts/ARC75.json examples/arc75/ && mocha --timeout 10000 -r ts-node/register 'examples/arc75/arc75_test.ts'", - "compile-examples": "yarn compile-amm && yarn compile-arc12 && yarn compile-arc75 && yarn compile-auction && yarn compile-itxns && yarn compile-simple && yarn compile-tuple_in_box" + "compile-examples": "yarn compile-amm && yarn compile-arc12 && yarn compile-arc75 && yarn compile-auction && yarn compile-itxns && yarn compile-simple && yarn compile-tuple_in_box && yarn compile-calculator" }, "dependencies": { "node-fetch": "2", diff --git a/pages/methods.md b/pages/methods.md index fd11bd61e..d4ffe9dc1 100644 --- a/pages/methods.md +++ b/pages/methods.md @@ -34,22 +34,20 @@ A method defined with the `private` keyword will only be accessible within the c In this example, there is a single public ABI method `doMath` which will then call the `add` or `subtract` subroutines depending on the method given. `doMath` is the only method that is externally callable. ```ts -private add (a: number, b: number): number { - return a + b +private getSum (a: number, b: number): number { + return a + b } -private subtract (a: number, b: number): number { - return a - b +private getDifference (a: number, b: number): number { + return a >= b ? a - b : b - a } doMath(a: number, b: number, operation: string): number { - if (operation === '+') { - this.add(a, b) - } else if (operation === '-') { - this.subtract(a, b) - } else { - err() - } + if (operation === 'sum') { + return this.getSum(a, b) + } else if (operation === 'difference') { + return this.getDifference(a, b) + } else throw Error('Invalid operation') } ``` @@ -60,7 +58,7 @@ TEALScript provides some decorators to allow for the handling of specific action ### Examples #### Bare Create ```ts -@createApplication +@handle.createApplication create(): void { log("This app has been created!") } @@ -68,7 +66,7 @@ create(): void { #### Non-Bare Create ```ts -@createApplication +@handle.createApplication create(name: string): void { log("This app has been created by " + name + "!") } @@ -77,8 +75,8 @@ create(name: string): void { `modifyApp` will allow both delete AND update on-completes. ```ts -@updateApplication -@deleteApplication +@handle.updateApplication +@handle.deleteApplication modifyApp(): void { assert(globals.creatorAddress === this.txn.sender) log("App is being modified!") diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index e0331c8bc..bbba01928 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -712,6 +712,8 @@ export default class Compiler { private getABIType(type: string): string { if (this.customTypes[type]) return type; const abiType = type.toLowerCase(); + if (type === 'number') return 'uint64'; + const typeNode = stringToExpression(type) as ts.Expression; if (abiType.match(/<\d+>$/)) { @@ -930,6 +932,14 @@ export default class Compiler { }); } + private processThrowStatement(node: ts.ThrowStatement) { + if (!ts.isCallExpression(node.expression)) throw Error('Must throw Error'); + if (node.expression.expression.getText() !== 'Error') throw Error('Must throw Error'); + + if (node.expression.arguments.length) this.pushVoid(`err // ${node.expression.arguments[0].getText()}`); + else this.pushVoid('err'); + } + private processNode(node: ts.Node) { this.pushComments(node); @@ -960,6 +970,7 @@ export default class Compiler { else if (ts.isNonNullExpression(node)) this.processNode(node.expression); else if (ts.isObjectLiteralExpression(node)) this.processObjectLiteralExpression(node); else if (node.kind === 108) this.lastType = 'this'; + else if (ts.isThrowStatement(node)) this.processThrowStatement(node); // Vars/Consts else if (ts.isIdentifier(node)) this.processIdentifier(node); diff --git a/tests/examples.test.ts b/tests/examples.test.ts index 52696a5a8..778ba2361 100644 --- a/tests/examples.test.ts +++ b/tests/examples.test.ts @@ -21,3 +21,5 @@ artifactsTest('Auction', 'examples/auction/auction.algo.ts', 'examples/auction/t artifactsTest('Simple', 'examples/simple/simple.algo.ts', 'examples/simple/artifacts/', 'Simple'); artifactsTest('Tuple In Box', 'examples/tuple_in_box/app.algo.ts', 'examples/tuple_in_box/tealscript_artifacts/', 'ContactsApp'); + +artifactsTest('Calculator', 'examples/calculator/calculator.algo.ts', 'examples/calculator/artifacts/', 'Calculator'); diff --git a/types/global.d.ts b/types/global.d.ts index d1e50a0f4..b1cf6f994 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -82,7 +82,7 @@ declare type bytes = string declare type StaticArray = T[] declare class Asset { - constructor(id: uint64) + static fromIndex(index: uint64): Asset; static readonly zeroIndex: Asset; @@ -112,7 +112,7 @@ declare class Asset { } declare class Address { - constructor(id: uint64) + static fromBytes(addr: BytesLike): Address; static readonly zeroAddress: Address; @@ -155,7 +155,7 @@ type Account = Address type BytesLike = bytes | Address declare class Application { - constructor(id: uint64) + static fromIndex(appID: uint64) static readonly zeroIndex: Application; @@ -421,7 +421,6 @@ declare function sendMethodCall( declare function btoi(byteslice: BytesLike): uint64 declare function itob(int: IntLike): bytes declare function log(content: BytesLike): void -declare function err() declare function sha256(arg0: BytesLike) declare function keccak256(arg0: BytesLike) declare function sha512_256(arg0: BytesLike)