From fc632e59fbb201679074b930bee31bb5d2a866f1 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 12:58:52 -0500 Subject: [PATCH 01/13] Tag all current Azle examples --- .../getting-started/default-template.mdx | 120 ++++---- .../getting-started/hello-world.mdx | 26 +- .../handling-get-post-requests.mdx | 282 +++++++++--------- .../advanced-features/management-canister.mdx | 14 +- .../advanced-features/periodic-tasks.mdx | 272 ++++++++--------- .../advanced-features/randomness.mdx | 52 ++-- .../serving-http-request.mdx | 98 +++--- .../advanced-features/time-and-timestamps.mdx | 16 +- .../smart-contracts/call/arguments.mdx | 82 ++--- .../smart-contracts/call/overview.mdx | 50 ++-- .../smart-contracts/deploy/overview.mdx | 262 ++++++++-------- 11 files changed, 637 insertions(+), 637 deletions(-) diff --git a/docs/developer-docs/getting-started/default-template.mdx b/docs/developer-docs/getting-started/default-template.mdx index 4f0eaea8b8..5f49650f28 100644 --- a/docs/developer-docs/getting-started/default-template.mdx +++ b/docs/developer-docs/getting-started/default-template.mdx @@ -79,31 +79,31 @@ hello/ }> ```bash -hello/ -├── README.md # Default project documentation -├── dfx.json # Project configuration file -├── node_modules # Libraries for frontend development -├── package-lock.json -├── package.json -├── src # Source files directory -│ ├── hello_backend -│ │ └── package.json -│ │ └── hello_backend.did -│ │ └── src -│ │ ├── index.ts -│ ├── hello_frontend -│ ├── assets -| |── index.html -| |── package.json -│ └── src -│ ├── App.js -│ ├── index.scss -│ ├── logo2.svg -│ ├── main.js -│ └── vite-env.d.ts -| |── tsconfig.json -| |── vite.config.js -└── tsconfig.json + hello/ + ├── README.md # Default project documentation + ├── dfx.json # Project configuration file + ├── node_modules # Libraries for frontend development + ├── package-lock.json + ├── package.json + ├── src # Source files directory + │ ├── hello_backend + │ │ └── package.json + │ │ └── hello_backend.did + │ │ └── src + │ │ ├── index.ts + │ ├── hello_frontend + │ ├── assets + | |── index.html + | |── package.json + │ └── src + │ ├── App.js + │ ├── index.scss + │ ├── logo2.svg + │ ├── main.js + │ └── vite-env.d.ts + | |── tsconfig.json + | |── vite.config.js + └── tsconfig.json ``` @@ -242,36 +242,36 @@ By default, the `dfx.json` file will contain automatically generated configurati }> ```json -{ - "canisters": { - "hello_backend": { - "build": "npx azle hello_backend", - "candid": "src/hello_backend/hello_backend.did", - "gzip": true, - "main": "src/hello_backend/src/index.ts", - "type": "custom", - "wasm": ".azle/hello_backend/hello_backend.wasm" + { + "canisters": { + "hello_backend": { + "build": "npx azle hello_backend", + "candid": "src/hello_backend/hello_backend.did", + "gzip": true, + "main": "src/hello_backend/src/index.ts", + "type": "custom", + "wasm": ".azle/hello_backend/hello_backend.wasm" + }, + "hello_frontend": { + "dependencies": [ + "hello_backend" + ], + "source": [ + "src/hello_frontend/dist" + ], + "type": "assets", + "workspace": "hello_frontend" + } }, - "hello_frontend": { - "dependencies": [ - "hello_backend" - ], - "source": [ - "src/hello_frontend/dist" - ], - "type": "assets", - "workspace": "hello_frontend" - } - }, - "defaults": { - "build": { - "args": "", - "packtool": "" - } - }, - "output_env_file": ".env", - "version": 1 -} + "defaults": { + "build": { + "args": "", + "packtool": "" + } + }, + "output_env_file": ".env", + "version": 1 + } ``` @@ -348,13 +348,13 @@ fn greet(name: String) -> String { }> ```typescript -import { Canister, query, text } from 'azle'; + import { Canister, query, text } from 'azle'; -export default Canister({ - greet: query([text], text, (name) => { - return `Hello, ${name}!`; - }) -}) + export default Canister({ + greet: query([text], text, (name) => { + return `Hello, ${name}!`; + }) + }) ``` diff --git a/docs/developer-docs/getting-started/hello-world.mdx b/docs/developer-docs/getting-started/hello-world.mdx index 45cf982976..9389495de4 100644 --- a/docs/developer-docs/getting-started/hello-world.mdx +++ b/docs/developer-docs/getting-started/hello-world.mdx @@ -194,13 +194,13 @@ fn greet(name: String) -> String { }> ```typescript title="src/hello_backend/src/index.ts" -import { Canister, query, text } from 'azle'; + import { Canister, query, text } from 'azle'; -export default Canister({ - greet: query([text], text, (name) => { - return `Hello, ${name}!`; - }) -}) + export default Canister({ + greet: query([text], text, (name) => { + return `Hello, ${name}!`; + }) + }) ``` @@ -272,15 +272,15 @@ Output: }> -```bash -dfx canister call hello_backend greet world -``` + ```bash + dfx canister call hello_backend greet world + ``` -Output: + Output: -``` -("Hello, world!") -``` + ``` + ("Hello, world!") + ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx index d4fd600e9e..eb3b7dc1e9 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx @@ -93,76 +93,76 @@ fn respond_to(req: Request<()>) -> http::Result> { Check out the [Rust documentation](https://docs.rs/ic-cdk/latest/ic_cdk/attr.query.html) for more info on query calls. - - -```typescript -import { - blob, - bool, - Canister, - Func, - nat16, - None, - Opt, - query, - Record, - text, - Tuple, - Variant, - Vec -} from 'azle'; - -const Token = Record({ - // add whatever fields you'd like - arbitrary_data: text -}); - -const StreamingCallbackHttpResponse = Record({ - body: blob, - token: Opt(Token) -}); - -export const Callback = Func([text], StreamingCallbackHttpResponse, 'query'); - -const CallbackStrategy = Record({ - callback: Callback, - token: Token -}); - -const StreamingStrategy = Variant({ - Callback: CallbackStrategy -}); - -type HeaderField = [text, text]; -const HeaderField = Tuple(text, text); - -const HttpResponse = Record({ - status_code: nat16, - headers: Vec(HeaderField), - body: blob, - streaming_strategy: Opt(StreamingStrategy), - upgrade: Opt(bool) -}); - -const HttpRequest = Record({ - method: text, - url: text, - headers: Vec(HeaderField), - body: blob, - certificate_version: Opt(nat16) -}); - -export default Canister({ - http_request: query([HttpRequest], HttpResponse, (req) => { - return { - status_code: 200, - headers: [], - body: Buffer.from('hello'), - streaming_strategy: None, - upgrade: None - }; - }) -}); + + + ```typescript + import { + blob, + bool, + Canister, + Func, + nat16, + None, + Opt, + query, + Record, + text, + Tuple, + Variant, + Vec + } from 'azle'; + + const Token = Record({ + // add whatever fields you'd like + arbitrary_data: text + }); + + const StreamingCallbackHttpResponse = Record({ + body: blob, + token: Opt(Token) + }); + + export const Callback = Func([text], StreamingCallbackHttpResponse, 'query'); + + const CallbackStrategy = Record({ + callback: Callback, + token: Token + }); + + const StreamingStrategy = Variant({ + Callback: CallbackStrategy + }); + + type HeaderField = [text, text]; + const HeaderField = Tuple(text, text); + + const HttpResponse = Record({ + status_code: nat16, + headers: Vec(HeaderField), + body: blob, + streaming_strategy: Opt(StreamingStrategy), + upgrade: Opt(bool) + }); + + const HttpRequest = Record({ + method: text, + url: text, + headers: Vec(HeaderField), + body: blob, + certificate_version: Opt(nat16) + }); + + export default Canister({ + http_request: query([HttpRequest], HttpResponse, (req) => { + return { + status_code: 200, + headers: [], + body: Buffer.from('hello'), + streaming_strategy: None, + upgrade: None + }; + }) + }); ``` @@ -290,77 +290,77 @@ fn respond_to(req: Request<()>) -> http::Result> { Check out the [Rust documentation](https://docs.rs/ic-cdk/latest/ic_cdk/attr.update.html) for more info on update calls. - - -```typescript -import { - blob, - bool, - Canister, - Func, - nat16, - None, - Opt, - Record, - text, - Tuple, - update, - Variant, - Vec -} from 'azle'; - -const Token = Record({ - // add whatever fields you'd like - arbitrary_data: text -}); - -const StreamingCallbackHttpResponse = Record({ - body: blob, - token: Opt(Token) -}); - -export const Callback = Func([text], StreamingCallbackHttpResponse, 'query'); - -const CallbackStrategy = Record({ - callback: Callback, - token: Token -}); - -const StreamingStrategy = Variant({ - Callback: CallbackStrategy -}); - -type HeaderField = [text, text]; -const HeaderField = Tuple(text, text); - -const HttpResponse = Record({ - status_code: nat16, - headers: Vec(HeaderField), - body: blob, - streaming_strategy: Opt(StreamingStrategy), - upgrade: Opt(bool) -}); - -const HttpRequest = Record({ - method: text, - url: text, - headers: Vec(HeaderField), - body: blob, - certificate_version: Opt(nat16) -}); - -export default Canister({ - http_request_update: update([HttpRequest], HttpResponse, (req) => { - return { - status_code: 200, - headers: [], - body: Buffer.from('hello'), - streaming_strategy: None, - upgrade: None - }; - }) -}); -``` + + + ```typescript + import { + blob, + bool, + Canister, + Func, + nat16, + None, + Opt, + Record, + text, + Tuple, + update, + Variant, + Vec + } from 'azle'; + + const Token = Record({ + // add whatever fields you'd like + arbitrary_data: text + }); + + const StreamingCallbackHttpResponse = Record({ + body: blob, + token: Opt(Token) + }); + + export const Callback = Func([text], StreamingCallbackHttpResponse, 'query'); + + const CallbackStrategy = Record({ + callback: Callback, + token: Token + }); + + const StreamingStrategy = Variant({ + Callback: CallbackStrategy + }); + + type HeaderField = [text, text]; + const HeaderField = Tuple(text, text); + + const HttpResponse = Record({ + status_code: nat16, + headers: Vec(HeaderField), + body: blob, + streaming_strategy: Opt(StreamingStrategy), + upgrade: Opt(bool) + }); + + const HttpRequest = Record({ + method: text, + url: text, + headers: Vec(HeaderField), + body: blob, + certificate_version: Opt(nat16) + }); + + export default Canister({ + http_request_update: update([HttpRequest], HttpResponse, (req) => { + return { + status_code: 200, + headers: [], + body: Buffer.from('hello'), + streaming_strategy: None, + upgrade: None + }; + }) + }); + ``` Check out the [Azle documentation](https://demergent-labs.github.io/azle/http.html) for more info on HTTP requests. diff --git a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx index b85dedca67..8e848f29ef 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx @@ -83,13 +83,13 @@ async fn install_code(canister_id: CanisterId, wasm_module: Vec) { }> -```typescript -createCanister: update([], CreateCanisterResult, async () => { - return await ic.call(managementCanister.create_canister, { - args: [{ settings: None, sender_canister_version: None }], - cycles: 50_000_000_000_000n - }); -}) + ```typescript + createCanister: update([], CreateCanisterResult, async () => { + return await ic.call(managementCanister.create_canister, { + args: [{ settings: None, sender_canister_version: None }], + cycles: 50_000_000_000_000n + }); + }) ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx index aa267677fd..7dba704cd6 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx @@ -101,32 +101,32 @@ fn post_upgrade() { }> ```typescript -import { - Canister, - Duration, - ic, - TimerId, - Tuple, - update -} from 'azle/experimental'; - -export default Canister({ - setTimers: update([Duration], Tuple(TimerId, TimerId), (delay) => { - const functionTimerId = ic.setTimer(delay, callback); - - const capturedValue = '🚩'; - - const closureTimerId = ic.setTimer(delay, () => { - console.log(`closure called and captured value ${capturedValue}`); - }); - - return [functionTimerId, closureTimerId]; - }) -}); - -function callback() { - console.log('callback called'); -} + import { + Canister, + Duration, + ic, + TimerId, + Tuple, + update + } from 'azle/experimental'; + + export default Canister({ + setTimers: update([Duration], Tuple(TimerId, TimerId), (delay) => { + const functionTimerId = ic.setTimer(delay, callback); + + const capturedValue = '🚩'; + + const closureTimerId = ic.setTimer(delay, () => { + console.log(`closure called and captured value ${capturedValue}`); + }); + + return [functionTimerId, closureTimerId]; + }) + }); + + function callback() { + console.log('callback called'); + } ``` @@ -216,121 +216,121 @@ fn post_upgrade() { }> -```typescript -import { - blob, - bool, - Canister, - Duration, - ic, - int8, - query, - Record, - text, - TimerId, - update, - Void -} from 'azle'; -import { managementCanister } from 'azle/canisters/management'; - -const StatusReport = Record({ - single: bool, - inline: int8, - capture: text, - repeat: int8, - singleCrossCanister: blob, - repeatCrossCanister: blob -}); - -const TimerIds = Record({ - single: TimerId, - inline: TimerId, - capture: TimerId, - repeat: TimerId, - singleCrossCanister: TimerId, - repeatCrossCanister: TimerId -}); - -let statusReport: typeof StatusReport = { - single: false, - inline: 0, - capture: '', - repeat: 0, - singleCrossCanister: Uint8Array.from([]), - repeatCrossCanister: Uint8Array.from([]) -}; + ```typescript + import { + blob, + bool, + Canister, + Duration, + ic, + int8, + query, + Record, + text, + TimerId, + update, + Void + } from 'azle'; + import { managementCanister } from 'azle/canisters/management'; + + const StatusReport = Record({ + single: bool, + inline: int8, + capture: text, + repeat: int8, + singleCrossCanister: blob, + repeatCrossCanister: blob + }); + + const TimerIds = Record({ + single: TimerId, + inline: TimerId, + capture: TimerId, + repeat: TimerId, + singleCrossCanister: TimerId, + repeatCrossCanister: TimerId + }); + + let statusReport: typeof StatusReport = { + single: false, + inline: 0, + capture: '', + repeat: 0, + singleCrossCanister: Uint8Array.from([]), + repeatCrossCanister: Uint8Array.from([]) + }; + + export default Canister({ + clearTimer: update([TimerId], Void, (timerId) => { + ic.clearTimer(timerId); + console.log(`timer ${timerId} cancelled`); + }), + setTimers: update([Duration, Duration], TimerIds, (delay, interval) => { + const capturedValue = '🚩'; + + const singleId = ic.setTimer(delay, oneTimeTimerCallback); + + const inlineId = ic.setTimer(delay, () => { + statusReport.inline = 1; + console.log('Inline timer called'); + }); + + const captureId = ic.setTimer(delay, () => { + statusReport.capture = capturedValue; + console.log(`Timer captured value ${capturedValue}`); + }); + + const repeatId = ic.setTimerInterval(interval, () => { + statusReport.repeat++; + console.log(`Repeating timer. Call ${statusReport.repeat}`); + }); + + const singleCrossCanisterId = ic.setTimer( + delay, + singleCrossCanisterTimerCallback + ); + + const repeatCrossCanisterId = ic.setTimerInterval( + interval, + repeatCrossCanisterTimerCallback + ); + + return { + single: singleId, + inline: inlineId, + capture: captureId, + repeat: repeatId, + singleCrossCanister: singleCrossCanisterId, + repeatCrossCanister: repeatCrossCanisterId + }; + }), + statusReport: query([], StatusReport, () => { + return statusReport; + }) + }); + + function oneTimeTimerCallback() { + statusReport.single = true; + console.log('oneTimeTimerCallback called'); + } -export default Canister({ - clearTimer: update([TimerId], Void, (timerId) => { - ic.clearTimer(timerId); - console.log(`timer ${timerId} cancelled`); - }), - setTimers: update([Duration, Duration], TimerIds, (delay, interval) => { - const capturedValue = '🚩'; - - const singleId = ic.setTimer(delay, oneTimeTimerCallback); - - const inlineId = ic.setTimer(delay, () => { - statusReport.inline = 1; - console.log('Inline timer called'); - }); - - const captureId = ic.setTimer(delay, () => { - statusReport.capture = capturedValue; - console.log(`Timer captured value ${capturedValue}`); - }); - - const repeatId = ic.setTimerInterval(interval, () => { - statusReport.repeat++; - console.log(`Repeating timer. Call ${statusReport.repeat}`); - }); - - const singleCrossCanisterId = ic.setTimer( - delay, - singleCrossCanisterTimerCallback - ); + async function singleCrossCanisterTimerCallback() { + console.log('singleCrossCanisterTimerCallback'); - const repeatCrossCanisterId = ic.setTimerInterval( - interval, - repeatCrossCanisterTimerCallback + statusReport.singleCrossCanister = await ic.call( + managementCanister.raw_rand ); + } - return { - single: singleId, - inline: inlineId, - capture: captureId, - repeat: repeatId, - singleCrossCanister: singleCrossCanisterId, - repeatCrossCanister: repeatCrossCanisterId - }; - }), - statusReport: query([], StatusReport, () => { - return statusReport; - }) -}); - -function oneTimeTimerCallback() { - statusReport.single = true; - console.log('oneTimeTimerCallback called'); -} - -async function singleCrossCanisterTimerCallback() { - console.log('singleCrossCanisterTimerCallback'); - - statusReport.singleCrossCanister = await ic.call( - managementCanister.raw_rand - ); -} - -async function repeatCrossCanisterTimerCallback() { - console.log('repeatCrossCanisterTimerCallback'); + async function repeatCrossCanisterTimerCallback() { + console.log('repeatCrossCanisterTimerCallback'); - statusReport.repeatCrossCanister = Uint8Array.from([ - ...statusReport.repeatCrossCanister, - ...(await ic.call(managementCanister.raw_rand)) - ]); -} -``` + statusReport.repeatCrossCanister = Uint8Array.from([ + ...statusReport.repeatCrossCanister, + ...(await ic.call(managementCanister.raw_rand)) + ]); + } + ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx index e4324a08ee..e711b9adda 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx @@ -51,47 +51,47 @@ In addition to the `raw_rand` method, Motoko offers a [Random module](/docs/curr - + ```rust let (randomBytes,): (Vec,) = ic_cdk::api::call(Principal.management_canister(), "raw_rand", ()).await?; ``` - + -```typescript -import { blob, Canister, ic, update } from 'azle'; -import { managementCanister } from 'azle/canisters/management'; + ```typescript + import { blob, Canister, ic, update } from 'azle'; + import { managementCanister } from 'azle/canisters/management'; -export default Canister({ - randomBytes: update([], blob, async () => { - return await ic.call(managementCanister.raw_rand); - }) -}); -``` - + export default Canister({ + randomBytes: update([], blob, async () => { + return await ic.call(managementCanister.raw_rand); + }) + }); + ``` + - + -```python -from kybra import Async, blob, CallResult, match, update, Variant -from kybra.canisters.management import management_canister + ```python + from kybra import Async, blob, CallResult, match, update, Variant + from kybra.canisters.management import management_canister -class RandomBytesResult(Variant, total=False): - Ok: blob - Err: str + class RandomBytesResult(Variant, total=False): + Ok: blob + Err: str -@update -def random_bytes() -> Async[RandomBytesResult]: - call_result: CallResult[blob] = yield management_canister.raw_rand() + @update + def random_bytes() -> Async[RandomBytesResult]: + call_result: CallResult[blob] = yield management_canister.raw_rand() - return match( - call_result, {"Ok": lambda ok: {"Ok": ok}, "Err": lambda err: {"Err": err}} - ) -``` + return match( + call_result, {"Ok": lambda ok: {"Ok": ok}, "Err": lambda err: {"Err": err}} + ) + ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx index 6c9dcd2077..8f61175558 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx @@ -111,57 +111,57 @@ fn http_request(req: HttpRequest) -> HttpResponse { - + ```typescript -import { - blob, - bool, - Canister, - Func, - nat16, - None, - Opt, - query, - Record, - text, - Tuple, - Variant, - Vec -} from 'azle'; - -type HeaderField = [text, text]; -const HeaderField = Tuple(text, text); - -const HttpResponse = Record({ - status_code: nat16, - headers: Vec(HeaderField), - body: blob, -}); - -const HttpRequest = Record({ - method: text, - url: text, - headers: Vec(HeaderField), - body: blob, -}); - -export default Canister({ - http_request: query([HttpRequest], HttpResponse, (req) => { - const path = req.url.pathname; - if(path == "/hello") { - return { - status_code: 200, - headers: [], - body: Buffer.from('hello, world!') - }; - } return { - body: Text.encodeUtf8("404 Not found :"); - headers: []; - status_code:404; - } - }) -}); + import { + blob, + bool, + Canister, + Func, + nat16, + None, + Opt, + query, + Record, + text, + Tuple, + Variant, + Vec + } from 'azle'; + + type HeaderField = [text, text]; + const HeaderField = Tuple(text, text); + + const HttpResponse = Record({ + status_code: nat16, + headers: Vec(HeaderField), + body: blob, + }); + + const HttpRequest = Record({ + method: text, + url: text, + headers: Vec(HeaderField), + body: blob, + }); + + export default Canister({ + http_request: query([HttpRequest], HttpResponse, (req) => { + const path = req.url.pathname; + if(path == "/hello") { + return { + status_code: 200, + headers: [], + body: Buffer.from('hello, world!') + }; + } return { + body: Text.encodeUtf8("404 Not found :"); + headers: []; + status_code:404; + } + }) + }); ``` To learn more about serving an HTTP request in Typescript, refer to [the Azle book reference on incoming HTTP requests](https://demergent-labs.github.io/azle/http.html). diff --git a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx index 882ecfcbc3..d74191f42a 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx @@ -51,14 +51,14 @@ let current_time = IC_API::time(); }> -```typescript -import { Canister, ic, nat64, query } from 'azle/experimental'; - -export default Canister({ -    time: query([], nat64, () => { -        return ic.time(); -    }) -}); + ```typescript + import { Canister, ic, nat64, query } from 'azle/experimental'; + + export default Canister({ +     time: query([], nat64, () => { +         return ic.time(); +     }) + }); ``` diff --git a/docs/developer-docs/smart-contracts/call/arguments.mdx b/docs/developer-docs/smart-contracts/call/arguments.mdx index 259c6d503a..09ac6be28c 100644 --- a/docs/developer-docs/smart-contracts/call/arguments.mdx +++ b/docs/developer-docs/smart-contracts/call/arguments.mdx @@ -71,15 +71,15 @@ fn get_numbers(numbers: Vec) -> Vec { Azle refers to the `Vec` type to represent the equivalent of an `array` in Typescript. This is because `Vec` aligns with the [Candid](/docs/current/developer-docs/smart-contracts/candid/candid-concepts) type. -```typescript -import { Canister, int32, Vec, query } from 'azle'; -let numbers = [0,1,2,3]; -export default Canister({ - get_numbers: query([Vec(int32], Vec(int32), () => { - return numbers; - }) -}); -``` + ```typescript + import { Canister, int32, Vec, query } from 'azle'; + let numbers = [0,1,2,3]; + export default Canister({ + get_numbers: query([Vec(int32], Vec(int32), () => { + return numbers; + }) + }); + ``` To learn more about the `Vec` object in Typescript via Azle, refer to [the Azle book reference on Vec](https://demergent-labs.github.io/azle/reference/candid/vec.html?highlight=array#vec). @@ -183,39 +183,39 @@ fn get_text(d: Day) -> &'static str { }> -```typescript -import { Canister, query, Variant } from 'azle'; - -const Day = Variant({ - Sun; - Mon; - Tue; - Wed; - Thu; - Fri; - Sat; -}); - -export default Canister({ - get_text: query([Day], Day, (d)) => { - switch (d) { - case Day.Sun: - return "Sunday"; - case Day.Mon: - return "Monday"; - case Day.Tue: - return "Tuesday"; - case Day.Wed: - return "Wednesday"; - case Day.Thu: - return "Thursday"; - case Day.Fri: - return "Friday"; - case Day.Sat: - return "Saturday"; + ```typescript + import { Canister, query, Variant } from 'azle'; + + const Day = Variant({ + Sun; + Mon; + Tue; + Wed; + Thu; + Fri; + Sat; + }); + + export default Canister({ + get_text: query([Day], Day, (d)) => { + switch (d) { + case Day.Sun: + return "Sunday"; + case Day.Mon: + return "Monday"; + case Day.Tue: + return "Tuesday"; + case Day.Wed: + return "Wednesday"; + case Day.Thu: + return "Thursday"; + case Day.Fri: + return "Friday"; + case Day.Sat: + return "Saturday"; + } } -} -}); + }); ``` To learn more about variants in Typescript via Azle, refer to [the Azle book reference on variants](https://demergent-labs.github.io/azle/reference/candid/variant.html?highlight=variant#variant). diff --git a/docs/developer-docs/smart-contracts/call/overview.mdx b/docs/developer-docs/smart-contracts/call/overview.mdx index 87fc8f7ff2..dfaf98b231 100644 --- a/docs/developer-docs/smart-contracts/call/overview.mdx +++ b/docs/developer-docs/smart-contracts/call/overview.mdx @@ -58,22 +58,22 @@ fn increment() { }> -```typescript -setMessage: update([text], Void, (newMessage) => { - message = newMessage; // This change will be persisted -}) -``` + ```typescript + setMessage: update([text], Void, (newMessage) => { + message = newMessage; // This change will be persisted + }) + ``` - + -}> + }> -```python -@update -def set_message(new_message: str) -> void: - global message - message = new_message -``` + ```python + @update + def set_message(new_message: str) -> void: + global message + message = new_message + ``` @@ -117,21 +117,21 @@ fn greet(name: String) -> String { }> -```typescript -getMessage: query([], text, () => { - return message; -}), -``` + ```typescript + getMessage: query([], text, () => { + return message; + }), + ``` - + -}> + }> -```python -@query -def get_message() -> str: - return message -``` + ```python + @query + def get_message() -> str: + return message + ``` diff --git a/docs/developer-docs/smart-contracts/deploy/overview.mdx b/docs/developer-docs/smart-contracts/deploy/overview.mdx index b4b4263bd5..e328babca4 100644 --- a/docs/developer-docs/smart-contracts/deploy/overview.mdx +++ b/docs/developer-docs/smart-contracts/deploy/overview.mdx @@ -197,143 +197,143 @@ fn init(timer_interval_secs: u64) { }> -This example creates a timer function that must be manually called once a -canister starts: - -```typescript -import { -  blob, -  bool, -  Canister, -  Duration, -  ic, -  int8, -  query, -  Record, -  serialize, -  text, -  TimerId, -  update, -  Void, -} from "azle"; -import { managementCanister } from "azle/canisters/management"; - -const StatusReport = Record({ -  single: bool, -  inline: int8, -  capture: text, -  repeat: int8, -  singleCrossCanister: blob, -  repeatCrossCanister: blob, -}); -type StatusReport = typeof StatusReport.tsType; - -const TimerIds = Record({ -  single: TimerId, -  inline: TimerId, -  capture: TimerId, -  repeat: TimerId, -  singleCrossCanister: TimerId, -  repeatCrossCanister: TimerId, -}); -type TimerIds = typeof TimerIds.tsType; - -let statusReport: StatusReport = { -  single: false, -  inline: 0, -  capture: "", -  repeat: 0, -  singleCrossCanister: Uint8Array.from([]), -  repeatCrossCanister: Uint8Array.from([]), -}; - -export default Canister({ -  clearTimer: update([TimerId], Void, (timerId) => { -    ic.clearTimer(timerId); -    console.log(`timer ${timerId} cancelled`); -  }), -  setTimers: update([Duration, Duration], TimerIds, (delay, interval) => { -    const capturedValue = "🚩"; - -    const singleId = ic.setTimer(delay, oneTimeTimerCallback); - -    const inlineId = ic.setTimer(delay, () => { -      statusReport.inline = 1; -      console.log("Inline timer called"); -    }); - -    const captureId = ic.setTimer(delay, () => { -      statusReport.capture = capturedValue; -      console.log(`Timer captured value ${capturedValue}`); -    }); - -    const repeatId = ic.setTimerInterval(interval, () => { -      statusReport.repeat++; -      console.log(`Repeating timer. Call ${statusReport.repeat}`); -    }); - -    const singleCrossCanisterId = ic.setTimer( -      delay, -      singleCrossCanisterTimerCallback -    ); - -    const repeatCrossCanisterId = ic.setTimerInterval( -      interval, -      repeatCrossCanisterTimerCallback -    ); - -    return { -      single: singleId, -      inline: inlineId, -      capture: captureId, -      repeat: repeatId, -      singleCrossCanister: singleCrossCanisterId, -      repeatCrossCanister: repeatCrossCanisterId, -    }; -  }), -  statusReport: query([], StatusReport, () => { -    return statusReport; -  }), -}); - -function oneTimeTimerCallback() { -  statusReport.single = true; -  console.log("oneTimeTimerCallback called"); -} - -async function singleCrossCanisterTimerCallback() { -  console.log("singleCrossCanisterTimerCallback"); - -  statusReport.singleCrossCanister = await getRandomness(); -} - -async function repeatCrossCanisterTimerCallback() { -  console.log("repeatCrossCanisterTimerCallback"); - -  statusReport.repeatCrossCanister = Uint8Array.from([ -    ...statusReport.repeatCrossCanister, -    ...(await getRandomness()), -  ]); -} - -async function getRandomness(): Promise { -  if (process.env.AZLE_TEST_FETCH === "true") { -    const response = await fetch(`icp://aaaaa-aa/raw_rand`); -    const responseJson = await response.json(); - -    return responseJson; -  } else { -    return await ic.call(managementCanister.raw_rand); -  } -} -``` + This example creates a timer function that must be manually called once a + canister starts: + + ```typescript + import { +   blob, +   bool, +   Canister, +   Duration, +   ic, +   int8, +   query, +   Record, +   serialize, +   text, +   TimerId, +   update, +   Void, + } from "azle"; + import { managementCanister } from "azle/canisters/management"; + + const StatusReport = Record({ +   single: bool, +   inline: int8, +   capture: text, +   repeat: int8, +   singleCrossCanister: blob, +   repeatCrossCanister: blob, + }); + type StatusReport = typeof StatusReport.tsType; + + const TimerIds = Record({ +   single: TimerId, +   inline: TimerId, +   capture: TimerId, +   repeat: TimerId, +   singleCrossCanister: TimerId, +   repeatCrossCanister: TimerId, + }); + type TimerIds = typeof TimerIds.tsType; + + let statusReport: StatusReport = { +   single: false, +   inline: 0, +   capture: "", +   repeat: 0, +   singleCrossCanister: Uint8Array.from([]), +   repeatCrossCanister: Uint8Array.from([]), + }; + + export default Canister({ +   clearTimer: update([TimerId], Void, (timerId) => { +     ic.clearTimer(timerId); +     console.log(`timer ${timerId} cancelled`); +   }), +   setTimers: update([Duration, Duration], TimerIds, (delay, interval) => { +     const capturedValue = "🚩"; + +     const singleId = ic.setTimer(delay, oneTimeTimerCallback); + +     const inlineId = ic.setTimer(delay, () => { +       statusReport.inline = 1; +       console.log("Inline timer called"); +     }); + +     const captureId = ic.setTimer(delay, () => { +       statusReport.capture = capturedValue; +       console.log(`Timer captured value ${capturedValue}`); +     }); + +     const repeatId = ic.setTimerInterval(interval, () => { +       statusReport.repeat++; +       console.log(`Repeating timer. Call ${statusReport.repeat}`); +     }); + +     const singleCrossCanisterId = ic.setTimer( +       delay, +       singleCrossCanisterTimerCallback +     ); + +     const repeatCrossCanisterId = ic.setTimerInterval( +       interval, +       repeatCrossCanisterTimerCallback +     ); + +     return { +       single: singleId, +       inline: inlineId, +       capture: captureId, +       repeat: repeatId, +       singleCrossCanister: singleCrossCanisterId, +       repeatCrossCanister: repeatCrossCanisterId, +     }; +   }), +   statusReport: query([], StatusReport, () => { +     return statusReport; +   }), + }); + + function oneTimeTimerCallback() { +   statusReport.single = true; +   console.log("oneTimeTimerCallback called"); + } + + async function singleCrossCanisterTimerCallback() { +   console.log("singleCrossCanisterTimerCallback"); + +   statusReport.singleCrossCanister = await getRandomness(); + } + + async function repeatCrossCanisterTimerCallback() { +   console.log("repeatCrossCanisterTimerCallback"); + +   statusReport.repeatCrossCanister = Uint8Array.from([ +     ...statusReport.repeatCrossCanister, +     ...(await getRandomness()), +   ]); + } + + async function getRandomness(): Promise { +   if (process.env.AZLE_TEST_FETCH === "true") { +     const response = await fetch(`icp://aaaaa-aa/raw_rand`); +     const responseJson = await response.json(); + +     return responseJson; +   } else { +     return await ic.call(managementCanister.raw_rand); +   } + } + ``` }> This example creates a timer function that must be manually called once a -cansiter starts: +canister starts: ```python from kybra import ( From 2788db76be5e643bc682b07a4aa0e8623af04c63 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 16:00:54 -0500 Subject: [PATCH 02/13] update azle examples --- .../getting-started/default-template.mdx | 104 +++--- .../getting-started/hello-world.mdx | 42 ++- .../handling-get-post-requests.mdx | 242 +++++++------- .../advanced-features/management-canister.mdx | 24 +- .../advanced-features/periodic-tasks.mdx | 279 ++++++++-------- .../advanced-features/randomness.mdx | 69 ++-- .../serving-http-request.mdx | 300 +++++++++++++++--- .../smart-contracts/call/arguments.mdx | 60 ++-- .../smart-contracts/call/overview.mdx | 52 +-- .../smart-contracts/deploy/overview.mdx | 243 +++++++------- 10 files changed, 806 insertions(+), 609 deletions(-) diff --git a/docs/developer-docs/getting-started/default-template.mdx b/docs/developer-docs/getting-started/default-template.mdx index 5f49650f28..10c7314fb2 100644 --- a/docs/developer-docs/getting-started/default-template.mdx +++ b/docs/developer-docs/getting-started/default-template.mdx @@ -80,30 +80,25 @@ hello/ ```bash hello/ - ├── README.md # Default project documentation - ├── dfx.json # Project configuration file - ├── node_modules # Libraries for frontend development - ├── package-lock.json - ├── package.json - ├── src # Source files directory - │ ├── hello_backend - │ │ └── package.json - │ │ └── hello_backend.did - │ │ └── src - │ │ ├── index.ts - │ ├── hello_frontend - │ ├── assets - | |── index.html - | |── package.json - │ └── src - │ ├── App.js - │ ├── index.scss - │ ├── logo2.svg - │ ├── main.js - │ └── vite-env.d.ts - | |── tsconfig.json - | |── vite.config.js - └── tsconfig.json +├── README.md # Default project documentation +├── dfx.json # Project configuration file +├── env.d.ts +├── jest.config.js +├── node_modules +├── package-lock.json # Libraries for frontend development +├── package.json +├── src # Source files directory +│   ├── hello_backend +| | └── index.ts +│   ├── declarations +│   ├── hello_frontend +│   │   ├── index.html +│   │   └── index.ts +├── test +│   ├── pretest.ts +│   ├── test.ts +│   └── tests.ts +└── tsconfig.json ``` @@ -242,36 +237,19 @@ By default, the `dfx.json` file will contain automatically generated configurati }> ```json - { +{ "canisters": { - "hello_backend": { - "build": "npx azle hello_backend", - "candid": "src/hello_backend/hello_backend.did", - "gzip": true, - "main": "src/hello_backend/src/index.ts", - "type": "custom", - "wasm": ".azle/hello_backend/hello_backend.wasm" - }, - "hello_frontend": { - "dependencies": [ - "hello_backend" - ], - "source": [ - "src/hello_frontend/dist" - ], - "type": "assets", - "workspace": "hello_frontend" - } - }, - "defaults": { - "build": { - "args": "", - "packtool": "" - } - }, - "output_env_file": ".env", - "version": 1 - } + "hello_backend": { + "type": "azle", + "main": "src/hello_backend/index.ts", + "candid_gen": "automatic", + "declarations": { + "output": "test/dfx_generated/hello_backend", + "node_compatibility": true + } + } + } +} ``` @@ -348,13 +326,21 @@ fn greet(name: String) -> String { }> ```typescript - import { Canister, query, text } from 'azle'; +import { IDL, query, update } from 'azle'; + +export default class { + message: string = 'Hello world!'; + + @query([], IDL.Text) + getMessage(): string { + return this.message; + } - export default Canister({ - greet: query([text], text, (name) => { - return `Hello, ${name}!`; - }) - }) + @update([IDL.Text]) + setMessage(message: string): void { + this.message = message; + } +} ``` diff --git a/docs/developer-docs/getting-started/hello-world.mdx b/docs/developer-docs/getting-started/hello-world.mdx index 9389495de4..7731198965 100644 --- a/docs/developer-docs/getting-started/hello-world.mdx +++ b/docs/developer-docs/getting-started/hello-world.mdx @@ -193,14 +193,30 @@ fn greet(name: String) -> String { }> +TypeScript canisters can be written using the Azle canister development kit. For Azle projects, you will need to install the Azle `dfx` extension: + +``` +npx azle install-dfx-extension +``` + +The default canister code for Azle projects contains the following code: + ```typescript title="src/hello_backend/src/index.ts" - import { Canister, query, text } from 'azle'; +import { IDL, query, update } from 'azle'; + +export default class { + message: string = 'Hello world!'; + + @query([], IDL.Text) + getMessage(): string { + return this.message; + } - export default Canister({ - greet: query([text], text, (name) => { - return `Hello, ${name}!`; - }) - }) + @update([IDL.Text]) + setMessage(message: string): void { + this.message = message; + } +} ``` @@ -272,15 +288,15 @@ Output: }> - ```bash - dfx canister call hello_backend greet world - ``` +```bash +dfx canister call hello_backend getMessage +``` - Output: +Output: - ``` - ("Hello, world!") - ``` +``` +("Hello world!") +``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx index eb3b7dc1e9..7af36dba79 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx @@ -95,78 +95,31 @@ Check out the [Rust documentation](https://docs.rs/ic-cdk/latest/ic_cdk/attr.que - ```typescript - import { - blob, - bool, - Canister, - Func, - nat16, - None, - Opt, - query, - Record, - text, - Tuple, - Variant, - Vec - } from 'azle'; - - const Token = Record({ - // add whatever fields you'd like - arbitrary_data: text - }); - - const StreamingCallbackHttpResponse = Record({ - body: blob, - token: Opt(Token) - }); +```typescript +import express from 'express'; - export const Callback = Func([text], StreamingCallbackHttpResponse, 'query'); - - const CallbackStrategy = Record({ - callback: Callback, - token: Token - }); - - const StreamingStrategy = Variant({ - Callback: CallbackStrategy - }); +const app = express(); - type HeaderField = [text, text]; - const HeaderField = Tuple(text, text); +app.use(express.json()); - const HttpResponse = Record({ - status_code: nat16, - headers: Vec(HeaderField), - body: blob, - streaming_strategy: Opt(StreamingStrategy), - upgrade: Opt(bool) +app.post('/https-outcall', async (_req, res) => { + const response = await fetch(`https://httpbin.org/headers`, { + headers: { + 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', + 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', + 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' + } }); + const responseJson = await response.json(); - const HttpRequest = Record({ - method: text, - url: text, - headers: Vec(HeaderField), - body: blob, - certificate_version: Opt(nat16) - }); + res.json(responseJson); +}); - export default Canister({ - http_request: query([HttpRequest], HttpResponse, (req) => { - return { - status_code: 200, - headers: [], - body: Buffer.from('hello'), - streaming_strategy: None, - upgrade: None - }; - }) - }); +app.listen(); ``` -Check out the [Azle documentation](https://demergent-labs.github.io/azle/http.html) for more info on HTTP requests. +Check out the [Azle documentation](https://demergent-labs.github.io/azle/fetch.html) for more info on HTTP requests. @@ -292,75 +245,102 @@ Check out the [Rust documentation](https://docs.rs/ic-cdk/latest/ic_cdk/attr.upd - ```typescript +```typescript import { - blob, - bool, - Canister, - Func, - nat16, - None, - Opt, - Record, - text, - Tuple, - update, - Variant, - Vec - } from 'azle'; - - const Token = Record({ - // add whatever fields you'd like - arbitrary_data: text - }); - - const StreamingCallbackHttpResponse = Record({ - body: blob, - token: Opt(Token) - }); - - export const Callback = Func([text], StreamingCallbackHttpResponse, 'query'); - - const CallbackStrategy = Record({ - callback: Callback, - token: Token - }); - - const StreamingStrategy = Variant({ - Callback: CallbackStrategy - }); - - type HeaderField = [text, text]; - const HeaderField = Tuple(text, text); - - const HttpResponse = Record({ - status_code: nat16, - headers: Vec(HeaderField), - body: blob, - streaming_strategy: Opt(StreamingStrategy), - upgrade: Opt(bool) - }); - - const HttpRequest = Record({ - method: text, - url: text, - headers: Vec(HeaderField), - body: blob, - certificate_version: Opt(nat16) - }); - - export default Canister({ - http_request_update: update([HttpRequest], HttpResponse, (req) => { - return { - status_code: 200, - headers: [], - body: Buffer.from('hello'), - streaming_strategy: None, - upgrade: None - }; - }) - }); - ``` + Canister, + ic, + Manual, + None, + Principal, + query, + Some, + text, + update +} from 'azle/experimental'; +import { + HttpResponse, + HttpTransformArgs, + managementCanister +} from 'azle/experimental/canisters/management'; + +export default Canister({ + xkcd: update([], text, async () => { + if (process.env.AZLE_TEST_FETCH) { + ic.setOutgoingHttpOptions({ + maxResponseBytes: 2_000n, + cycles: 50_000_000n, + transformMethodName: 'xkcdTransform' + }); + + const response = await fetch(`https://xkcd.com/642/info.0.json`); + const responseText = await response.text(); + + return responseText; + } else { + const httpResponse = await ic.call( + managementCanister.http_request, + { + args: [ + { + url: `https://xkcd.com/642/info.0.json`, + max_response_bytes: Some(2_000n), + method: { + get: null + }, + headers: [], + body: None, + transform: Some({ + function: [ic.id(), 'xkcdTransform'] as [ + Principal, + string + ], + context: Uint8Array.from([]) + }) + } + ], + cycles: 50_000_000n + } + ); + + return Buffer.from(httpResponse.body).toString(); + } + }), + xkcdRaw: update( + [], + Manual(HttpResponse), + async () => { + const httpResponse = await ic.callRaw( + Principal.fromText('aaaaa-aa'), + 'http_request', + ic.candidEncode(` + ( + record { + url = "https://xkcd.com/642/info.0.json"; + max_response_bytes = 2_000 : nat64; + method = variant { get }; + headers = vec {}; + body = null; + transform = record { function = func "${ic + .id() + .toString()}".xkcdTransform; context = vec {} }; + } + ) + `), + 50_000_000n + ); + + ic.reply({ raw: httpResponse }); + }, + { manual: true } + ), + xkcdTransform: query([HttpTransformArgs], HttpResponse, (args) => { + return { + ...args.response, + headers: [] + }; + }) +}); +``` Check out the [Azle documentation](https://demergent-labs.github.io/azle/http.html) for more info on HTTP requests. diff --git a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx index 8e848f29ef..ad975a3fcb 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx @@ -83,13 +83,23 @@ async fn install_code(canister_id: CanisterId, wasm_module: Vec) { }> - ```typescript - createCanister: update([], CreateCanisterResult, async () => { - return await ic.call(managementCanister.create_canister, { - args: [{ settings: None, sender_canister_version: None }], - cycles: 50_000_000_000_000n - }); - }) +```typescript +async function createCanister(): Promise { + if (process.env.AZLE_TEST_FETCH === 'true') { + const response = await fetch(`icp://aaaaa-aa/create_canister`, { + body: serialize({ + args: [{ settings: [], sender_canister_version: [] }], + cycles: 50_000_000_000_000n + }) + }); + return await response.json(); + } else { + return await ic.call(managementCanister.create_canister, { + args: [{ settings: None, sender_canister_version: None }], + cycles: 50_000_000_000_000n + }); + } +} ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx index 7dba704cd6..17de967683 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx @@ -101,33 +101,32 @@ fn post_upgrade() { }> ```typescript - import { - Canister, - Duration, - ic, - TimerId, - Tuple, - update - } from 'azle/experimental'; - - export default Canister({ - setTimers: update([Duration], Tuple(TimerId, TimerId), (delay) => { - const functionTimerId = ic.setTimer(delay, callback); - - const capturedValue = '🚩'; - - const closureTimerId = ic.setTimer(delay, () => { - console.log(`closure called and captured value ${capturedValue}`); - }); - - return [functionTimerId, closureTimerId]; - }) - }); - - function callback() { - console.log('callback called'); - } +import { + Canister, + Duration, + ic, + TimerId, + Tuple, + update +} from 'azle/experimental'; + +export default Canister({ + setTimers: update([Duration], Tuple(TimerId, TimerId), (delay) => { + const functionTimerId = ic.setTimer(delay, callback); + + const capturedValue = '🚩'; + + const closureTimerId = ic.setTimer(delay, () => { + console.log(`closure called and captured value ${capturedValue}`); + }); + + return [functionTimerId, closureTimerId]; + }) +}); +function callback() { + console.log('callback called'); +} ``` @@ -216,121 +215,131 @@ fn post_upgrade() { }> - ```typescript - import { - blob, - bool, - Canister, - Duration, - ic, - int8, - query, - Record, - text, - TimerId, - update, - Void - } from 'azle'; - import { managementCanister } from 'azle/canisters/management'; - - const StatusReport = Record({ - single: bool, - inline: int8, - capture: text, - repeat: int8, - singleCrossCanister: blob, - repeatCrossCanister: blob - }); - - const TimerIds = Record({ - single: TimerId, - inline: TimerId, - capture: TimerId, - repeat: TimerId, - singleCrossCanister: TimerId, - repeatCrossCanister: TimerId - }); - - let statusReport: typeof StatusReport = { - single: false, - inline: 0, - capture: '', - repeat: 0, - singleCrossCanister: Uint8Array.from([]), - repeatCrossCanister: Uint8Array.from([]) - }; - - export default Canister({ - clearTimer: update([TimerId], Void, (timerId) => { - ic.clearTimer(timerId); - console.log(`timer ${timerId} cancelled`); - }), - setTimers: update([Duration, Duration], TimerIds, (delay, interval) => { - const capturedValue = '🚩'; - - const singleId = ic.setTimer(delay, oneTimeTimerCallback); - - const inlineId = ic.setTimer(delay, () => { - statusReport.inline = 1; - console.log('Inline timer called'); - }); - - const captureId = ic.setTimer(delay, () => { - statusReport.capture = capturedValue; - console.log(`Timer captured value ${capturedValue}`); - }); - - const repeatId = ic.setTimerInterval(interval, () => { - statusReport.repeat++; - console.log(`Repeating timer. Call ${statusReport.repeat}`); - }); - - const singleCrossCanisterId = ic.setTimer( - delay, - singleCrossCanisterTimerCallback - ); - - const repeatCrossCanisterId = ic.setTimerInterval( - interval, - repeatCrossCanisterTimerCallback - ); - - return { - single: singleId, - inline: inlineId, - capture: captureId, - repeat: repeatId, - singleCrossCanister: singleCrossCanisterId, - repeatCrossCanister: repeatCrossCanisterId - }; - }), - statusReport: query([], StatusReport, () => { - return statusReport; - }) - }); - - function oneTimeTimerCallback() { - statusReport.single = true; - console.log('oneTimeTimerCallback called'); - } +```typescript +import { + blob, + bool, + Canister, + ic, + int8, + nat64, + query, + Record, + text, + update, + Void +} from 'azle/experimental'; +import { managementCanister } from 'azle/experimental/canisters/management'; + +const StatusReport = Record({ + single: bool, + inline: int8, + capture: text, + repeat: int8, + singleCrossCanister: blob, + repeatCrossCanister: blob +}); +type StatusReport = typeof StatusReport.tsType; + +const TimerIds = Record({ + single: nat64, + inline: nat64, + capture: nat64, + repeat: nat64, + singleCrossCanister: nat64, + repeatCrossCanister: nat64 +}); +type TimerIds = typeof TimerIds.tsType; + +let statusReport: StatusReport = { + single: false, + inline: 0, + capture: '', + repeat: 0, + singleCrossCanister: Uint8Array.from([]), + repeatCrossCanister: Uint8Array.from([]) +}; - async function singleCrossCanisterTimerCallback() { - console.log('singleCrossCanisterTimerCallback'); +export default Canister({ + clearTimer: update([nat64], Void, (timerId) => { + ic.clearTimer(timerId); + console.info(`timer ${timerId} cancelled`); + }), + setTimers: update([nat64, nat64], TimerIds, (delay, interval) => { + const capturedValue = '🚩'; + + const singleId = ic.setTimer(delay, oneTimeTimerCallback); + + const inlineId = ic.setTimer(delay, () => { + statusReport.inline = 1; + console.info('Inline timer called'); + }); + + const captureId = ic.setTimer(delay, () => { + statusReport.capture = capturedValue; + console.info(`Timer captured value ${capturedValue}`); + }); + + const repeatId = ic.setTimerInterval(interval, () => { + statusReport.repeat++; + console.info(`Repeating timer. Call ${statusReport.repeat}`); + }); + + const singleCrossCanisterId = ic.setTimer( + delay, + singleCrossCanisterTimerCallback + ); - statusReport.singleCrossCanister = await ic.call( - managementCanister.raw_rand + const repeatCrossCanisterId = ic.setTimerInterval( + interval, + repeatCrossCanisterTimerCallback ); - } - async function repeatCrossCanisterTimerCallback() { - console.log('repeatCrossCanisterTimerCallback'); + return { + single: singleId, + inline: inlineId, + capture: captureId, + repeat: repeatId, + singleCrossCanister: singleCrossCanisterId, + repeatCrossCanister: repeatCrossCanisterId + }; + }), + statusReport: query([], StatusReport, () => { + return statusReport; + }) +}); + +function oneTimeTimerCallback(): void { + statusReport.single = true; + console.info('oneTimeTimerCallback called'); +} + +async function singleCrossCanisterTimerCallback(): Promise { + console.info('singleCrossCanisterTimerCallback'); + + statusReport.singleCrossCanister = await getRandomness(); +} + +async function repeatCrossCanisterTimerCallback(): Promise { + console.info('repeatCrossCanisterTimerCallback'); + + statusReport.repeatCrossCanister = Uint8Array.from([ + ...statusReport.repeatCrossCanister, + ...(await getRandomness()) + ]); +} - statusReport.repeatCrossCanister = Uint8Array.from([ - ...statusReport.repeatCrossCanister, - ...(await ic.call(managementCanister.raw_rand)) - ]); +async function getRandomness(): Promise { + if (process.env.AZLE_TEST_FETCH === 'true') { + const response = await fetch(`icp://aaaaa-aa/raw_rand`); + const responseJson = await response.json(); + + return responseJson; + } else { + return await ic.call(managementCanister.raw_rand); } - ``` +} +``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx index e711b9adda..73a5d89154 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx @@ -58,41 +58,56 @@ let (randomBytes,): (Vec,) = ic_cdk::api::call(Principal.management_canister ``` - - - ```typescript - import { blob, Canister, ic, update } from 'azle'; - import { managementCanister } from 'azle/canisters/management'; +}> + +```typescript +import { + bool, + Canister, + float64, + postUpgrade, + query, + update +} from 'azle/experimental'; + +let redeployed = false; + +export default Canister({ + postUpgrade: postUpgrade([], () => { + redeployed = true; + }), + getRedeployed: query([], bool, () => { + return redeployed; + }), + randomNumber: update([], float64, () => { + return Math.random(); + }) +}); +``` - export default Canister({ - randomBytes: update([], blob, async () => { - return await ic.call(managementCanister.raw_rand); - }) - }); - ``` - + - +}> - ```python - from kybra import Async, blob, CallResult, match, update, Variant - from kybra.canisters.management import management_canister +```python +from kybra import Async, blob, CallResult, match, update, Variant +from kybra.canisters.management import management_canister - class RandomBytesResult(Variant, total=False): - Ok: blob - Err: str +class RandomBytesResult(Variant, total=False): + Ok: blob + Err: str - @update - def random_bytes() -> Async[RandomBytesResult]: - call_result: CallResult[blob] = yield management_canister.raw_rand() +@update +def random_bytes() -> Async[RandomBytesResult]: + call_result: CallResult[blob] = yield management_canister.raw_rand() - return match( - call_result, {"Ok": lambda ok: {"Ok": ok}, "Err": lambda err: {"Err": err}} - ) - ``` + return match( + call_result, {"Ok": lambda ok: {"Ok": ok}, "Err": lambda err: {"Err": err}} + ) +``` - + diff --git a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx index 8f61175558..3242a075ef 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx @@ -111,62 +111,268 @@ fn http_request(req: HttpRequest) -> HttpResponse { - +}> + +To serve HTTP requests, you can use the Azle `http-server` functionality by creating a new project with the flag `--http-server`: + +``` +npx azle new http_requests --http-server +cd http_requests +``` + +Then, use the `fetch` functionality to create an HTTP server that can process incoming requests: + ```typescript - import { - blob, - bool, - Canister, - Func, - nat16, - None, - Opt, - query, - Record, - text, - Tuple, - Variant, - Vec - } from 'azle'; - - type HeaderField = [text, text]; - const HeaderField = Tuple(text, text); - - const HttpResponse = Record({ - status_code: nat16, - headers: Vec(HeaderField), - body: blob, - }); - - const HttpRequest = Record({ - method: text, - url: text, - headers: Vec(HeaderField), - body: blob, - }); - - export default Canister({ - http_request: query([HttpRequest], HttpResponse, (req) => { - const path = req.url.pathname; - if(path == "/hello") { +import { ic, query, Server } from 'azle/experimental'; +import { + HttpResponse, + HttpTransformArgs +} from 'azle/experimental/canisters/management'; +import express from 'express'; + +export default Server( + () => { + const app = express(); + + app.use(express.json()); + + app.get('/fetch-head', async (_req, res) => { + const response = await fetch( + `https://cat-fact.herokuapp.com/facts/591f989cd369931519ce361d`, + { + method: 'HEAD' + } + ); + + res.json(Array.from(response.headers.entries())); + }); + + app.get('/fetch-get', async (_req, res) => { + const response = await fetch( + `https://cat-fact.herokuapp.com/facts/591f989cd369931519ce361d` + ); + + res.json({ + headers: Array.from(response.headers.entries()), + body: await response.json() + }); + }); + + app.get('/fetch-get-query-params', async (_req, res) => { + const response = await fetch( + `https://cat-fact.herokuapp.com/facts/random?amount=2` + ); + + res.json(await response.json()); + }); + + app.post('/fetch-post', async (_req, res) => { + const response = await fetch(new URL('https://rpc.ankr.com/eth'), { + method: 'POST', + body: JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_getBalance', + params: [ + '0xeac0827eff0c6e3ff28a7d4a54f65cb7689d7b99', + 'earliest' + ], + id: 1 + }) + }); + const responseJson = await response.json(); + + res.json(responseJson); + }); + + app.get('/request-headers', async (_req, res) => { + const response = await fetch(`https://httpbin.org/headers`, { + headers: { + 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', + 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', + 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' + } + }); + const responseJson = await response.json(); + + res.json(responseJson); + }); + + app.get('/get-status-201', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/201`); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.post('/get-status-205', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/205`, { + method: 'POST' + }); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.get('/get-status-301', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/301`); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.post('/get-status-304', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/304`, { + method: 'POST' + }); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.get('/get-status-401', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/401`); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.post('/get-status-418', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/418`, { + method: 'POST' + }); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.get('/get-status-500', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/500`); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.post('/get-status-501', async (_req, res) => { + const response = await fetch(`https://httpbin.org/status/501`, { + method: 'POST' + }); + + res.json({ + status: response.status, + statusText: response.statusText + }); + }); + + app.get('/transform', async (_req, res) => { + ic.setOutgoingHttpOptions({ + transformMethodName: 'transform' + }); + + const response = await fetch(`https://httpbin.org/headers`, { + headers: { + 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', + 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', + 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' + } + }); + + res.json(Array.from(response.headers.entries())); + }); + + app.get('/transform-with-context', async (_req, res) => { + ic.setOutgoingHttpOptions({ + transformMethodName: 'transform', + transformContext: Uint8Array.from([0, 1, 2]) + }); + + const response = await fetch(`https://httpbin.org/headers`, { + headers: { + 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', + 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', + 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' + } + }); + + res.json({ + headers: Array.from(response.headers.entries()), + body: (await response.arrayBuffer()).byteLength + }); + }); + + app.get('/max-response-bytes', async (_req, res) => { + try { + ic.setOutgoingHttpOptions({ + maxResponseBytes: 0n + }); + + const response = await fetch( + `https://httpbin.org/get?hello=world` + ); + + res.json({ + headers: Array.from(response.headers.entries()), + body: (await response.arrayBuffer()).byteLength + }); + } catch (error) { + res.json(error); + } + }); + + app.get('/cycles', async (_req, res) => { + try { + ic.setOutgoingHttpOptions({ + cycles: 0n + }); + + const response = await fetch( + `https://httpbin.org/get?hello=world` + ); + + res.json({ + headers: Array.from(response.headers.entries()), + body: (await response.arrayBuffer()).byteLength + }); + } catch (error) { + res.json(error); + } + }); + + return app.listen(); + }, + { + transform: query( + [HttpTransformArgs], + HttpResponse, + (httpTransformArgs) => { return { - status_code: 200, + ...httpTransformArgs.response, headers: [], - body: Buffer.from('hello, world!') + body: httpTransformArgs.context }; - } return { - body: Text.encodeUtf8("404 Not found :"); - headers: []; - status_code:404; } - }) - }); + ) + } +); ``` -To learn more about serving an HTTP request in Typescript, refer to [the Azle book reference on incoming HTTP requests](https://demergent-labs.github.io/azle/http.html). +To learn more about serving an HTTP request in Typescript, refer to [the Azle book reference on fetch](https://demergent-labs.github.io/azle/fetch.html). - + }> diff --git a/docs/developer-docs/smart-contracts/call/arguments.mdx b/docs/developer-docs/smart-contracts/call/arguments.mdx index 09ac6be28c..a63935acf7 100644 --- a/docs/developer-docs/smart-contracts/call/arguments.mdx +++ b/docs/developer-docs/smart-contracts/call/arguments.mdx @@ -71,15 +71,22 @@ fn get_numbers(numbers: Vec) -> Vec { Azle refers to the `Vec` type to represent the equivalent of an `array` in Typescript. This is because `Vec` aligns with the [Candid](/docs/current/developer-docs/smart-contracts/candid/candid-concepts) type. - ```typescript - import { Canister, int32, Vec, query } from 'azle'; - let numbers = [0,1,2,3]; - export default Canister({ - get_numbers: query([Vec(int32], Vec(int32), () => { - return numbers; - }) - }); - ``` +```typescript +import { blob, Canister, query, Vec } from 'azle/experimental'; + +export default Canister({ + getBlob: query([], blob, () => { + return stringToBlob('hello'); + }), + getBlobs: query([], Vec(blob), () => { + return [stringToBlob('hello'), stringToBlob('world')]; + }) +}); + +function stringToBlob(string: string): blob { + return Buffer.from(string); +} +``` To learn more about the `Vec` object in Typescript via Azle, refer to [the Azle book reference on Vec](https://demergent-labs.github.io/azle/reference/candid/vec.html?highlight=array#vec). @@ -183,39 +190,8 @@ fn get_text(d: Day) -> &'static str { }> - ```typescript - import { Canister, query, Variant } from 'azle'; - - const Day = Variant({ - Sun; - Mon; - Tue; - Wed; - Thu; - Fri; - Sat; - }); - - export default Canister({ - get_text: query([Day], Day, (d)) => { - switch (d) { - case Day.Sun: - return "Sunday"; - case Day.Mon: - return "Monday"; - case Day.Tue: - return "Tuesday"; - case Day.Wed: - return "Wednesday"; - case Day.Thu: - return "Thursday"; - case Day.Fri: - return "Friday"; - case Day.Sat: - return "Saturday"; - } - } - }); +```typescript + ``` To learn more about variants in Typescript via Azle, refer to [the Azle book reference on variants](https://demergent-labs.github.io/azle/reference/candid/variant.html?highlight=variant#variant). diff --git a/docs/developer-docs/smart-contracts/call/overview.mdx b/docs/developer-docs/smart-contracts/call/overview.mdx index dfaf98b231..9c8ac41ee7 100644 --- a/docs/developer-docs/smart-contracts/call/overview.mdx +++ b/docs/developer-docs/smart-contracts/call/overview.mdx @@ -58,22 +58,24 @@ fn increment() { }> - ```typescript - setMessage: update([text], Void, (newMessage) => { - message = newMessage; // This change will be persisted - }) - ``` +```typescript +incrementCount: update([], nat64, () => { + count += 1n; - + return count; +}) +``` + + - }> +}> - ```python - @update - def set_message(new_message: str) -> void: - global message - message = new_message - ``` +```python +@update +def set_message(new_message: str) -> void: + global message + message = new_message +``` @@ -117,21 +119,21 @@ fn greet(name: String) -> String { }> - ```typescript - getMessage: query([], text, () => { - return message; - }), - ``` +```typescript +readCount: query([], nat64, () => { + return count; +}), +``` - + - }> +}> - ```python - @query - def get_message() -> str: - return message - ``` +```python +@query +def get_message() -> str: + return message +``` diff --git a/docs/developer-docs/smart-contracts/deploy/overview.mdx b/docs/developer-docs/smart-contracts/deploy/overview.mdx index e328babca4..6f1d133a20 100644 --- a/docs/developer-docs/smart-contracts/deploy/overview.mdx +++ b/docs/developer-docs/smart-contracts/deploy/overview.mdx @@ -197,136 +197,133 @@ fn init(timer_interval_secs: u64) { }> - This example creates a timer function that must be manually called once a - canister starts: - - ```typescript - import { -   blob, -   bool, -   Canister, -   Duration, -   ic, -   int8, -   query, -   Record, -   serialize, -   text, -   TimerId, -   update, -   Void, - } from "azle"; - import { managementCanister } from "azle/canisters/management"; - - const StatusReport = Record({ -   single: bool, -   inline: int8, -   capture: text, -   repeat: int8, -   singleCrossCanister: blob, -   repeatCrossCanister: blob, - }); - type StatusReport = typeof StatusReport.tsType; - - const TimerIds = Record({ -   single: TimerId, -   inline: TimerId, -   capture: TimerId, -   repeat: TimerId, -   singleCrossCanister: TimerId, -   repeatCrossCanister: TimerId, - }); - type TimerIds = typeof TimerIds.tsType; - - let statusReport: StatusReport = { -   single: false, -   inline: 0, -   capture: "", -   repeat: 0, -   singleCrossCanister: Uint8Array.from([]), -   repeatCrossCanister: Uint8Array.from([]), - }; - - export default Canister({ -   clearTimer: update([TimerId], Void, (timerId) => { -     ic.clearTimer(timerId); -     console.log(`timer ${timerId} cancelled`); -   }), -   setTimers: update([Duration, Duration], TimerIds, (delay, interval) => { -     const capturedValue = "🚩"; - -     const singleId = ic.setTimer(delay, oneTimeTimerCallback); - -     const inlineId = ic.setTimer(delay, () => { -       statusReport.inline = 1; -       console.log("Inline timer called"); -     }); - -     const captureId = ic.setTimer(delay, () => { -       statusReport.capture = capturedValue; -       console.log(`Timer captured value ${capturedValue}`); -     }); - -     const repeatId = ic.setTimerInterval(interval, () => { -       statusReport.repeat++; -       console.log(`Repeating timer. Call ${statusReport.repeat}`); -     }); - -     const singleCrossCanisterId = ic.setTimer( -       delay, -       singleCrossCanisterTimerCallback -     ); - -     const repeatCrossCanisterId = ic.setTimerInterval( -       interval, -       repeatCrossCanisterTimerCallback -     ); - -     return { -       single: singleId, -       inline: inlineId, -       capture: captureId, -       repeat: repeatId, -       singleCrossCanister: singleCrossCanisterId, -       repeatCrossCanister: repeatCrossCanisterId, -     }; -   }), -   statusReport: query([], StatusReport, () => { -     return statusReport; -   }), - }); - - function oneTimeTimerCallback() { -   statusReport.single = true; -   console.log("oneTimeTimerCallback called"); - } +This example creates a timer function that must be manually called once a canister starts: + +```typescript +import { + blob, + bool, + Canister, + ic, + int8, + nat64, + query, + Record, + text, + update, + Void +} from 'azle/experimental'; +import { managementCanister } from 'azle/experimental/canisters/management'; + +const StatusReport = Record({ + single: bool, + inline: int8, + capture: text, + repeat: int8, + singleCrossCanister: blob, + repeatCrossCanister: blob +}); +type StatusReport = typeof StatusReport.tsType; + +const TimerIds = Record({ + single: nat64, + inline: nat64, + capture: nat64, + repeat: nat64, + singleCrossCanister: nat64, + repeatCrossCanister: nat64 +}); +type TimerIds = typeof TimerIds.tsType; + +let statusReport: StatusReport = { + single: false, + inline: 0, + capture: '', + repeat: 0, + singleCrossCanister: Uint8Array.from([]), + repeatCrossCanister: Uint8Array.from([]) +}; + +export default Canister({ + clearTimer: update([nat64], Void, (timerId) => { + ic.clearTimer(timerId); + console.info(`timer ${timerId} cancelled`); + }), + setTimers: update([nat64, nat64], TimerIds, (delay, interval) => { + const capturedValue = '🚩'; + + const singleId = ic.setTimer(delay, oneTimeTimerCallback); + + const inlineId = ic.setTimer(delay, () => { + statusReport.inline = 1; + console.info('Inline timer called'); + }); + + const captureId = ic.setTimer(delay, () => { + statusReport.capture = capturedValue; + console.info(`Timer captured value ${capturedValue}`); + }); + + const repeatId = ic.setTimerInterval(interval, () => { + statusReport.repeat++; + console.info(`Repeating timer. Call ${statusReport.repeat}`); + }); + + const singleCrossCanisterId = ic.setTimer( + delay, + singleCrossCanisterTimerCallback + ); + + const repeatCrossCanisterId = ic.setTimerInterval( + interval, + repeatCrossCanisterTimerCallback + ); + + return { + single: singleId, + inline: inlineId, + capture: captureId, + repeat: repeatId, + singleCrossCanister: singleCrossCanisterId, + repeatCrossCanister: repeatCrossCanisterId + }; + }), + statusReport: query([], StatusReport, () => { + return statusReport; + }) +}); + +function oneTimeTimerCallback(): void { + statusReport.single = true; + console.info('oneTimeTimerCallback called'); +} - async function singleCrossCanisterTimerCallback() { -   console.log("singleCrossCanisterTimerCallback"); +async function singleCrossCanisterTimerCallback(): Promise { + console.info('singleCrossCanisterTimerCallback'); -   statusReport.singleCrossCanister = await getRandomness(); - } + statusReport.singleCrossCanister = await getRandomness(); +} - async function repeatCrossCanisterTimerCallback() { -   console.log("repeatCrossCanisterTimerCallback"); +async function repeatCrossCanisterTimerCallback(): Promise { + console.info('repeatCrossCanisterTimerCallback'); -   statusReport.repeatCrossCanister = Uint8Array.from([ -     ...statusReport.repeatCrossCanister, -     ...(await getRandomness()), -   ]); - } + statusReport.repeatCrossCanister = Uint8Array.from([ + ...statusReport.repeatCrossCanister, + ...(await getRandomness()) + ]); +} - async function getRandomness(): Promise { -   if (process.env.AZLE_TEST_FETCH === "true") { -     const response = await fetch(`icp://aaaaa-aa/raw_rand`); -     const responseJson = await response.json(); +async function getRandomness(): Promise { + if (process.env.AZLE_TEST_FETCH === 'true') { + const response = await fetch(`icp://aaaaa-aa/raw_rand`); + const responseJson = await response.json(); -     return responseJson; -   } else { -     return await ic.call(managementCanister.raw_rand); -   } + return responseJson; + } else { + return await ic.call(managementCanister.raw_rand); } - ``` +} +``` From 52abacdd244629906485bb5668d38c2dd282fe9b Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 16:19:00 -0500 Subject: [PATCH 03/13] update azle examples --- .../advanced-features/periodic-tasks.mdx | 27 +------------------ .../advanced-features/time-and-timestamps.mdx | 13 ++++----- .../smart-contracts/call/arguments.mdx | 9 +++++-- 3 files changed, 13 insertions(+), 36 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx index 17de967683..d56b5a6396 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx @@ -101,32 +101,7 @@ fn post_upgrade() { }> ```typescript -import { - Canister, - Duration, - ic, - TimerId, - Tuple, - update -} from 'azle/experimental'; - -export default Canister({ - setTimers: update([Duration], Tuple(TimerId, TimerId), (delay) => { - const functionTimerId = ic.setTimer(delay, callback); - - const capturedValue = '🚩'; - - const closureTimerId = ic.setTimer(delay, () => { - console.log(`closure called and captured value ${capturedValue}`); - }); - - return [functionTimerId, closureTimerId]; - }) -}); - -function callback() { - console.log('callback called'); -} +const timerId = setTimer(1_000, () => console.log('timer callback called')); ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx index d74191f42a..a86955067c 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx @@ -51,14 +51,11 @@ let current_time = IC_API::time(); }> - ```typescript - import { Canister, ic, nat64, query } from 'azle/experimental'; - - export default Canister({ -     time: query([], nat64, () => { -         return ic.time(); -     }) - }); +```typescript + @query([], IDL.Nat64) + time(): bigint { + return time(); + } ``` diff --git a/docs/developer-docs/smart-contracts/call/arguments.mdx b/docs/developer-docs/smart-contracts/call/arguments.mdx index a63935acf7..caa861eadd 100644 --- a/docs/developer-docs/smart-contracts/call/arguments.mdx +++ b/docs/developer-docs/smart-contracts/call/arguments.mdx @@ -89,7 +89,7 @@ function stringToBlob(string: string): blob { ``` -To learn more about the `Vec` object in Typescript via Azle, refer to [the Azle book reference on Vec](https://demergent-labs.github.io/azle/reference/candid/vec.html?highlight=array#vec). +To learn more about the `Vec` object in Typescript via Azle, refer to [the Azle documentation](https://demergent-labs.github.io/azle/). @@ -191,9 +191,14 @@ fn get_text(d: Day) -> &'static str { }> ```typescript +export const ReactionType = IDL.Variant({ + Fire: IDL.Null, + ThumbsUp: IDL.Null, + ThumbsDown: IDL.Null +}); ``` -To learn more about variants in Typescript via Azle, refer to [the Azle book reference on variants](https://demergent-labs.github.io/azle/reference/candid/variant.html?highlight=variant#variant). +To learn more about variants in Typescript via Azle, refer to [the Azle code](https://github.com/demergent-labs/azle/blob/main/tests/end_to_end/candid_rpc/class_syntax/complex_types/src/candid_types.ts#L3). From 396f237b1423debf81a4a62267758189bf4bbc68 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 16:55:39 -0500 Subject: [PATCH 04/13] update azle examples --- blog/news-and-updates/2024-07-31-update.mdx | 0 .../advanced-features/management-canister.mdx | 22 ++-- .../advanced-features/periodic-tasks.mdx | 117 ++++++++++-------- .../advanced-features/time-and-timestamps.mdx | 8 +- .../smart-contracts/call/arguments.mdx | 19 +-- .../smart-contracts/deploy/overview.mdx | 117 ++++++++++-------- 6 files changed, 148 insertions(+), 135 deletions(-) create mode 100644 blog/news-and-updates/2024-07-31-update.mdx diff --git a/blog/news-and-updates/2024-07-31-update.mdx b/blog/news-and-updates/2024-07-31-update.mdx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx index ad975a3fcb..16e3e45662 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx @@ -84,21 +84,13 @@ async fn install_code(canister_id: CanisterId, wasm_module: Vec) { }> ```typescript -async function createCanister(): Promise { - if (process.env.AZLE_TEST_FETCH === 'true') { - const response = await fetch(`icp://aaaaa-aa/create_canister`, { - body: serialize({ - args: [{ settings: [], sender_canister_version: [] }], - cycles: 50_000_000_000_000n - }) - }); - return await response.json(); - } else { - return await ic.call(managementCanister.create_canister, { - args: [{ settings: None, sender_canister_version: None }], - cycles: 50_000_000_000_000n - }); - } +@update([], CreateCanisterResult) +async executeCreateCanister(): Promise { + const createCanisterResult = await createCanister(); + + state.createdCanisterId = createCanisterResult.canister_id; + + return createCanisterResult; } ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx index d56b5a6396..a04a4a15f5 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx @@ -192,39 +192,48 @@ fn post_upgrade() { ```typescript import { - blob, - bool, - Canister, - ic, - int8, - nat64, + call, + clearTimer, + IDL, query, - Record, - text, - update, - Void -} from 'azle/experimental'; -import { managementCanister } from 'azle/experimental/canisters/management'; - -const StatusReport = Record({ - single: bool, - inline: int8, - capture: text, - repeat: int8, - singleCrossCanister: blob, - repeatCrossCanister: blob + setTimer, + setTimerInterval, + update +} from 'azle'; + +const StatusReport = IDL.Record({ + single: IDL.Bool, + inline: IDL.Int8, + capture: IDL.Text, + repeat: IDL.Int8, + singleCrossCanister: IDL.Vec(IDL.Nat8), + repeatCrossCanister: IDL.Vec(IDL.Nat8) }); -type StatusReport = typeof StatusReport.tsType; - -const TimerIds = Record({ - single: nat64, - inline: nat64, - capture: nat64, - repeat: nat64, - singleCrossCanister: nat64, - repeatCrossCanister: nat64 +type StatusReport = { + single: boolean; + inline: number; + capture: string; + repeat: number; + singleCrossCanister: Uint8Array; + repeatCrossCanister: Uint8Array; +}; + +const TimerIds = IDL.Record({ + single: IDL.Nat64, + inline: IDL.Nat64, + capture: IDL.Nat64, + repeat: IDL.Nat64, + singleCrossCanister: IDL.Nat64, + repeatCrossCanister: IDL.Nat64 }); -type TimerIds = typeof TimerIds.tsType; +type TimerIds = { + single: bigint; + inline: bigint; + capture: bigint; + repeat: bigint; + singleCrossCanister: bigint; + repeatCrossCanister: bigint; +}; let statusReport: StatusReport = { single: false, @@ -235,37 +244,40 @@ let statusReport: StatusReport = { repeatCrossCanister: Uint8Array.from([]) }; -export default Canister({ - clearTimer: update([nat64], Void, (timerId) => { - ic.clearTimer(timerId); +export default class { + @update([IDL.Nat64]) + clearTimer(timerId: bigint): void { + clearTimer(timerId); console.info(`timer ${timerId} cancelled`); - }), - setTimers: update([nat64, nat64], TimerIds, (delay, interval) => { + } + + @update([IDL.Nat64, IDL.Nat64], TimerIds) + setTimers(delay: bigint, interval: bigint): TimerIds { const capturedValue = '🚩'; - const singleId = ic.setTimer(delay, oneTimeTimerCallback); + const singleId = setTimer(delay, oneTimeTimerCallback); - const inlineId = ic.setTimer(delay, () => { + const inlineId = setTimer(delay, () => { statusReport.inline = 1; console.info('Inline timer called'); }); - const captureId = ic.setTimer(delay, () => { + const captureId = setTimer(delay, () => { statusReport.capture = capturedValue; console.info(`Timer captured value ${capturedValue}`); }); - const repeatId = ic.setTimerInterval(interval, () => { + const repeatId = setTimerInterval(interval, () => { statusReport.repeat++; console.info(`Repeating timer. Call ${statusReport.repeat}`); }); - const singleCrossCanisterId = ic.setTimer( + const singleCrossCanisterId = setTimer( delay, singleCrossCanisterTimerCallback ); - const repeatCrossCanisterId = ic.setTimerInterval( + const repeatCrossCanisterId = setTimerInterval( interval, repeatCrossCanisterTimerCallback ); @@ -278,11 +290,13 @@ export default Canister({ singleCrossCanister: singleCrossCanisterId, repeatCrossCanister: repeatCrossCanisterId }; - }), - statusReport: query([], StatusReport, () => { + } + + @query([], StatusReport) + statusReport(): StatusReport { return statusReport; - }) -}); + } +} function oneTimeTimerCallback(): void { statusReport.single = true; @@ -304,15 +318,10 @@ async function repeatCrossCanisterTimerCallback(): Promise { ]); } -async function getRandomness(): Promise { - if (process.env.AZLE_TEST_FETCH === 'true') { - const response = await fetch(`icp://aaaaa-aa/raw_rand`); - const responseJson = await response.json(); - - return responseJson; - } else { - return await ic.call(managementCanister.raw_rand); - } +async function getRandomness(): Promise { + return await call('aaaaa-aa', 'raw_rand', { + returnIdlType: IDL.Vec(IDL.Nat8) + }); } ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx index a86955067c..8f92226bf2 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx @@ -52,10 +52,10 @@ let current_time = IC_API::time(); }> ```typescript - @query([], IDL.Nat64) - time(): bigint { - return time(); - } +@query([], IDL.Nat64) +time(): bigint { + return time(); +} ``` diff --git a/docs/developer-docs/smart-contracts/call/arguments.mdx b/docs/developer-docs/smart-contracts/call/arguments.mdx index caa861eadd..5110c43092 100644 --- a/docs/developer-docs/smart-contracts/call/arguments.mdx +++ b/docs/developer-docs/smart-contracts/call/arguments.mdx @@ -72,18 +72,21 @@ fn get_numbers(numbers: Vec) -> Vec { Azle refers to the `Vec` type to represent the equivalent of an `array` in Typescript. This is because `Vec` aligns with the [Candid](/docs/current/developer-docs/smart-contracts/candid/candid-concepts) type. ```typescript -import { blob, Canister, query, Vec } from 'azle/experimental'; +import { IDL, query } from 'azle'; -export default Canister({ - getBlob: query([], blob, () => { +export default class { + @query([], IDL.Vec(IDL.Nat8)) + getBlob(): Uint8Array { return stringToBlob('hello'); - }), - getBlobs: query([], Vec(blob), () => { + } + + @query([], IDL.Vec(IDL.Vec(IDL.Nat8))) + getBlobs(): Uint8Array[] { return [stringToBlob('hello'), stringToBlob('world')]; - }) -}); + } +} -function stringToBlob(string: string): blob { +function stringToBlob(string: string): Uint8Array { return Buffer.from(string); } ``` diff --git a/docs/developer-docs/smart-contracts/deploy/overview.mdx b/docs/developer-docs/smart-contracts/deploy/overview.mdx index 6f1d133a20..2b391134c3 100644 --- a/docs/developer-docs/smart-contracts/deploy/overview.mdx +++ b/docs/developer-docs/smart-contracts/deploy/overview.mdx @@ -201,39 +201,48 @@ This example creates a timer function that must be manually called once a canist ```typescript import { - blob, - bool, - Canister, - ic, - int8, - nat64, + call, + clearTimer, + IDL, query, - Record, - text, - update, - Void -} from 'azle/experimental'; -import { managementCanister } from 'azle/experimental/canisters/management'; - -const StatusReport = Record({ - single: bool, - inline: int8, - capture: text, - repeat: int8, - singleCrossCanister: blob, - repeatCrossCanister: blob + setTimer, + setTimerInterval, + update +} from 'azle'; + +const StatusReport = IDL.Record({ + single: IDL.Bool, + inline: IDL.Int8, + capture: IDL.Text, + repeat: IDL.Int8, + singleCrossCanister: IDL.Vec(IDL.Nat8), + repeatCrossCanister: IDL.Vec(IDL.Nat8) }); -type StatusReport = typeof StatusReport.tsType; - -const TimerIds = Record({ - single: nat64, - inline: nat64, - capture: nat64, - repeat: nat64, - singleCrossCanister: nat64, - repeatCrossCanister: nat64 +type StatusReport = { + single: boolean; + inline: number; + capture: string; + repeat: number; + singleCrossCanister: Uint8Array; + repeatCrossCanister: Uint8Array; +}; + +const TimerIds = IDL.Record({ + single: IDL.Nat64, + inline: IDL.Nat64, + capture: IDL.Nat64, + repeat: IDL.Nat64, + singleCrossCanister: IDL.Nat64, + repeatCrossCanister: IDL.Nat64 }); -type TimerIds = typeof TimerIds.tsType; +type TimerIds = { + single: bigint; + inline: bigint; + capture: bigint; + repeat: bigint; + singleCrossCanister: bigint; + repeatCrossCanister: bigint; +}; let statusReport: StatusReport = { single: false, @@ -244,37 +253,40 @@ let statusReport: StatusReport = { repeatCrossCanister: Uint8Array.from([]) }; -export default Canister({ - clearTimer: update([nat64], Void, (timerId) => { - ic.clearTimer(timerId); +export default class { + @update([IDL.Nat64]) + clearTimer(timerId: bigint): void { + clearTimer(timerId); console.info(`timer ${timerId} cancelled`); - }), - setTimers: update([nat64, nat64], TimerIds, (delay, interval) => { + } + + @update([IDL.Nat64, IDL.Nat64], TimerIds) + setTimers(delay: bigint, interval: bigint): TimerIds { const capturedValue = '🚩'; - const singleId = ic.setTimer(delay, oneTimeTimerCallback); + const singleId = setTimer(delay, oneTimeTimerCallback); - const inlineId = ic.setTimer(delay, () => { + const inlineId = setTimer(delay, () => { statusReport.inline = 1; console.info('Inline timer called'); }); - const captureId = ic.setTimer(delay, () => { + const captureId = setTimer(delay, () => { statusReport.capture = capturedValue; console.info(`Timer captured value ${capturedValue}`); }); - const repeatId = ic.setTimerInterval(interval, () => { + const repeatId = setTimerInterval(interval, () => { statusReport.repeat++; console.info(`Repeating timer. Call ${statusReport.repeat}`); }); - const singleCrossCanisterId = ic.setTimer( + const singleCrossCanisterId = setTimer( delay, singleCrossCanisterTimerCallback ); - const repeatCrossCanisterId = ic.setTimerInterval( + const repeatCrossCanisterId = setTimerInterval( interval, repeatCrossCanisterTimerCallback ); @@ -287,11 +299,13 @@ export default Canister({ singleCrossCanister: singleCrossCanisterId, repeatCrossCanister: repeatCrossCanisterId }; - }), - statusReport: query([], StatusReport, () => { + } + + @query([], StatusReport) + statusReport(): StatusReport { return statusReport; - }) -}); + } +} function oneTimeTimerCallback(): void { statusReport.single = true; @@ -313,15 +327,10 @@ async function repeatCrossCanisterTimerCallback(): Promise { ]); } -async function getRandomness(): Promise { - if (process.env.AZLE_TEST_FETCH === 'true') { - const response = await fetch(`icp://aaaaa-aa/raw_rand`); - const responseJson = await response.json(); - - return responseJson; - } else { - return await ic.call(managementCanister.raw_rand); - } +async function getRandomness(): Promise { + return await call('aaaaa-aa', 'raw_rand', { + returnIdlType: IDL.Vec(IDL.Nat8) + }); } ``` From 121ecbfda3390e7eb048540d91ff9f6e97d685ea Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 17:07:42 -0500 Subject: [PATCH 05/13] update azle examples --- .../handling-get-post-requests.mdx | 248 +++++++++++------- 1 file changed, 148 insertions(+), 100 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx index 7af36dba79..4a4cfa119a 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx @@ -93,33 +93,94 @@ fn respond_to(req: Request<()>) -> http::Result> { Check out the [Rust documentation](https://docs.rs/ic-cdk/latest/ic_cdk/attr.query.html) for more info on query calls. - +}> ```typescript -import express from 'express'; - -const app = express(); +import { + call, + candidEncode, + id, + IDL, + Principal, + query, + reply, + update +} from 'azle'; +import { + HttpRequestArgs, + HttpResponse, + HttpTransformArgs +} from 'azle/canisters/management'; + +export default class { + @update([], IDL.Text) + async xkcd(): Promise { + const httpResponse = await call('aaaaa-aa', 'http_request', { + paramIdlTypes: [HttpRequestArgs], + returnIdlType: HttpResponse, + args: [ + { + url: `https://xkcd.com/642/info.0.json`, + max_response_bytes: [2_000n], + method: { + get: null + }, + headers: [], + body: [], + transform: [ + { + function: [id(), 'xkcdTransform'] as [ + Principal, + string + ], + context: Uint8Array.from([]) + } + ] + } + ], + payment: 50_000_000n + }); -app.use(express.json()); + return Buffer.from(httpResponse.body).toString(); + } -app.post('/https-outcall', async (_req, res) => { - const response = await fetch(`https://httpbin.org/headers`, { - headers: { - 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', - 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', - 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' - } - }); - const responseJson = await response.json(); + @update([], HttpResponse, { manual: true }) + async xkcdRaw(): Promise { + const httpResponse = await call( + Principal.fromText('aaaaa-aa'), + 'http_request', + { + raw: candidEncode(` + ( + record { + url = "https://xkcd.com/642/info.0.json"; + max_response_bytes = 2_000 : nat64; + method = variant { get }; + headers = vec {}; + body = null; + transform = record { function = func "${id().toString()}".xkcdTransform; context = vec {} }; + } + ) + `), + payment: 50_000_000n + } + ); - res.json(responseJson); -}); + reply({ raw: httpResponse }); + } -app.listen(); + @query([HttpTransformArgs], HttpResponse) + xkcdTransform(args: HttpTransformArgs): HttpResponse { + return { + ...args.response, + headers: [] + }; + } +} ``` -Check out the [Azle documentation](https://demergent-labs.github.io/azle/fetch.html) for more info on HTTP requests. +Check out the [Azle documentation](https://github.com/demergent-labs/azle/tree/main/tests/end_to_end/candid_rpc/class_syntax/outgoing_http_requests) for more info on HTTP requests. @@ -243,106 +304,93 @@ fn respond_to(req: Request<()>) -> http::Result> { Check out the [Rust documentation](https://docs.rs/ic-cdk/latest/ic_cdk/attr.update.html) for more info on update calls. - +}> ```typescript - import { - Canister, - ic, - Manual, - None, +import { + call, + candidEncode, + id, + IDL, Principal, query, - Some, - text, + reply, update -} from 'azle/experimental'; +} from 'azle'; import { + HttpRequestArgs, HttpResponse, - HttpTransformArgs, - managementCanister -} from 'azle/experimental/canisters/management'; - -export default Canister({ - xkcd: update([], text, async () => { - if (process.env.AZLE_TEST_FETCH) { - ic.setOutgoingHttpOptions({ - maxResponseBytes: 2_000n, - cycles: 50_000_000n, - transformMethodName: 'xkcdTransform' - }); - - const response = await fetch(`https://xkcd.com/642/info.0.json`); - const responseText = await response.text(); - - return responseText; - } else { - const httpResponse = await ic.call( - managementCanister.http_request, + HttpTransformArgs +} from 'azle/canisters/management'; + +export default class { + @update([], IDL.Text) + async xkcd(): Promise { + const httpResponse = await call('aaaaa-aa', 'http_request', { + paramIdlTypes: [HttpRequestArgs], + returnIdlType: HttpResponse, + args: [ { - args: [ + url: `https://xkcd.com/642/info.0.json`, + max_response_bytes: [2_000n], + method: { + get: null + }, + headers: [], + body: [], + transform: [ { - url: `https://xkcd.com/642/info.0.json`, - max_response_bytes: Some(2_000n), - method: { - get: null - }, - headers: [], - body: None, - transform: Some({ - function: [ic.id(), 'xkcdTransform'] as [ - Principal, - string - ], - context: Uint8Array.from([]) - }) + function: [id(), 'xkcdTransform'] as [ + Principal, + string + ], + context: Uint8Array.from([]) } - ], - cycles: 50_000_000n + ] } - ); + ], + payment: 50_000_000n + }); - return Buffer.from(httpResponse.body).toString(); - } - }), - xkcdRaw: update( - [], - Manual(HttpResponse), - async () => { - const httpResponse = await ic.callRaw( - Principal.fromText('aaaaa-aa'), - 'http_request', - ic.candidEncode(` - ( - record { - url = "https://xkcd.com/642/info.0.json"; - max_response_bytes = 2_000 : nat64; - method = variant { get }; - headers = vec {}; - body = null; - transform = record { function = func "${ic - .id() - .toString()}".xkcdTransform; context = vec {} }; - } - ) - `), - 50_000_000n - ); - - ic.reply({ raw: httpResponse }); - }, - { manual: true } - ), - xkcdTransform: query([HttpTransformArgs], HttpResponse, (args) => { + return Buffer.from(httpResponse.body).toString(); + } + + @update([], HttpResponse, { manual: true }) + async xkcdRaw(): Promise { + const httpResponse = await call( + Principal.fromText('aaaaa-aa'), + 'http_request', + { + raw: candidEncode(` + ( + record { + url = "https://xkcd.com/642/info.0.json"; + max_response_bytes = 2_000 : nat64; + method = variant { get }; + headers = vec {}; + body = null; + transform = record { function = func "${id().toString()}".xkcdTransform; context = vec {} }; + } + ) + `), + payment: 50_000_000n + } + ); + + reply({ raw: httpResponse }); + } + + @query([HttpTransformArgs], HttpResponse) + xkcdTransform(args: HttpTransformArgs): HttpResponse { return { ...args.response, headers: [] }; - }) -}); + } +} ``` -Check out the [Azle documentation](https://demergent-labs.github.io/azle/http.html) for more info on HTTP requests. +Check out the [Azle documentation](https://github.com/demergent-labs/azle/tree/main/tests/end_to_end/candid_rpc/class_syntax/outgoing_http_requests) for more info on HTTP requests. From 06eb819b74f88f61feed76ea469aa5532c0fa076 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 17:08:22 -0500 Subject: [PATCH 06/13] update azle examples --- blog/news-and-updates/2024-07-31-update.mdx | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 blog/news-and-updates/2024-07-31-update.mdx diff --git a/blog/news-and-updates/2024-07-31-update.mdx b/blog/news-and-updates/2024-07-31-update.mdx deleted file mode 100644 index e69de29bb2..0000000000 From c788b552914a61c48961fa28f5d90893d4dffaf9 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 17:11:00 -0500 Subject: [PATCH 07/13] update azle examples --- .../advanced-features/randomness.mdx | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx index 73a5d89154..1032480364 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx @@ -61,28 +61,26 @@ let (randomBytes,): (Vec,) = ic_cdk::api::call(Principal.management_canister }> ```typescript -import { - bool, - Canister, - float64, - postUpgrade, - query, - update -} from 'azle/experimental'; +import { IDL, postUpgrade, query, update } from 'azle'; let redeployed = false; -export default Canister({ - postUpgrade: postUpgrade([], () => { +export default class { + @postUpgrade([]) + postUpgrade(): void { redeployed = true; - }), - getRedeployed: query([], bool, () => { + } + + @query([], IDL.Bool) + getRedeployed(): boolean { return redeployed; - }), - randomNumber: update([], float64, () => { + } + + @update([], IDL.Float64) + randomNumber(): number { return Math.random(); - }) -}); + } +} ``` From 19414e8b1aee8cea074b11a899150470c33dc26b Mon Sep 17 00:00:00 2001 From: Jessie Mongeon <133128541+jessiemongeon1@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:51:54 -0500 Subject: [PATCH 08/13] Update serving-http-request.mdx --- .../serving-http-request.mdx | 288 +++--------------- 1 file changed, 46 insertions(+), 242 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx index 3242a075ef..e69feaba65 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx @@ -124,250 +124,54 @@ Then, use the `fetch` functionality to create an HTTP server that can process in ```typescript -import { ic, query, Server } from 'azle/experimental'; import { - HttpResponse, - HttpTransformArgs -} from 'azle/experimental/canisters/management'; -import express from 'express'; - -export default Server( - () => { - const app = express(); - - app.use(express.json()); - - app.get('/fetch-head', async (_req, res) => { - const response = await fetch( - `https://cat-fact.herokuapp.com/facts/591f989cd369931519ce361d`, - { - method: 'HEAD' - } - ); - - res.json(Array.from(response.headers.entries())); - }); - - app.get('/fetch-get', async (_req, res) => { - const response = await fetch( - `https://cat-fact.herokuapp.com/facts/591f989cd369931519ce361d` - ); - - res.json({ - headers: Array.from(response.headers.entries()), - body: await response.json() - }); - }); - - app.get('/fetch-get-query-params', async (_req, res) => { - const response = await fetch( - `https://cat-fact.herokuapp.com/facts/random?amount=2` - ); - - res.json(await response.json()); - }); - - app.post('/fetch-post', async (_req, res) => { - const response = await fetch(new URL('https://rpc.ankr.com/eth'), { - method: 'POST', - body: JSON.stringify({ - jsonrpc: '2.0', - method: 'eth_getBalance', - params: [ - '0xeac0827eff0c6e3ff28a7d4a54f65cb7689d7b99', - 'earliest' - ], - id: 1 - }) - }); - const responseJson = await response.json(); - - res.json(responseJson); - }); - - app.get('/request-headers', async (_req, res) => { - const response = await fetch(`https://httpbin.org/headers`, { - headers: { - 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', - 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', - 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' - } - }); - const responseJson = await response.json(); - - res.json(responseJson); - }); - - app.get('/get-status-201', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/201`); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.post('/get-status-205', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/205`, { - method: 'POST' - }); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.get('/get-status-301', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/301`); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.post('/get-status-304', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/304`, { - method: 'POST' - }); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.get('/get-status-401', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/401`); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.post('/get-status-418', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/418`, { - method: 'POST' - }); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.get('/get-status-500', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/500`); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.post('/get-status-501', async (_req, res) => { - const response = await fetch(`https://httpbin.org/status/501`, { - method: 'POST' - }); - - res.json({ - status: response.status, - statusText: response.statusText - }); - }); - - app.get('/transform', async (_req, res) => { - ic.setOutgoingHttpOptions({ - transformMethodName: 'transform' - }); - - const response = await fetch(`https://httpbin.org/headers`, { - headers: { - 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', - 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', - 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' - } - }); - - res.json(Array.from(response.headers.entries())); - }); - - app.get('/transform-with-context', async (_req, res) => { - ic.setOutgoingHttpOptions({ - transformMethodName: 'transform', - transformContext: Uint8Array.from([0, 1, 2]) - }); - - const response = await fetch(`https://httpbin.org/headers`, { - headers: { - 'X-Azle-Request-Key-0': 'X-Azle-Request-Value-0', - 'X-Azle-Request-Key-1': 'X-Azle-Request-Value-1', - 'X-Azle-Request-Key-2': 'X-Azle-Request-Value-2' - } - }); - - res.json({ - headers: Array.from(response.headers.entries()), - body: (await response.arrayBuffer()).byteLength - }); - }); - - app.get('/max-response-bytes', async (_req, res) => { - try { - ic.setOutgoingHttpOptions({ - maxResponseBytes: 0n - }); - - const response = await fetch( - `https://httpbin.org/get?hello=world` - ); - - res.json({ - headers: Array.from(response.headers.entries()), - body: (await response.arrayBuffer()).byteLength - }); - } catch (error) { - res.json(error); - } - }); - - app.get('/cycles', async (_req, res) => { - try { - ic.setOutgoingHttpOptions({ - cycles: 0n - }); - - const response = await fetch( - `https://httpbin.org/get?hello=world` - ); - - res.json({ - headers: Array.from(response.headers.entries()), - body: (await response.arrayBuffer()).byteLength - }); - } catch (error) { - res.json(error); - } - }); - - return app.listen(); - }, - { - transform: query( - [HttpTransformArgs], - HttpResponse, - (httpTransformArgs) => { - return { - ...httpTransformArgs.response, - headers: [], - body: httpTransformArgs.context - }; - } - ) + blob, + bool, + Canister, + Func, + nat16, + None, + Opt, + query, + Record, + text, + Tuple, + Variant, + Vec +} from 'azle'; + +type HeaderField = [text, text]; +const HeaderField = Tuple(text, text); + +const HttpResponse = Record({ + status_code: nat16, + headers: Vec(HeaderField), + body: blob, +}); + +const HttpRequest = Record({ + method: text, + url: text, + headers: Vec(HeaderField), + body: blob, +}); + +export default class{ + http_request: @query([HttpRequest], HttpResponse, (req) => { + const path = req.url.pathname; + if(path == "/hello") { + return { + status_code: 200, + headers: [], + body: Buffer.from('hello, world!') + }; + } return { + body: Text.encodeUtf8("404 Not found :"); + headers: []; + status_code:404; + } } -); +}); ``` To learn more about serving an HTTP request in Typescript, refer to [the Azle book reference on fetch](https://demergent-labs.github.io/azle/fetch.html). From 81980c005360a9fe2c38e03ab96793c1b2b51415 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 31 Jul 2024 18:48:58 -0500 Subject: [PATCH 09/13] apply code feedback --- .../getting-started/default-template.mdx | 7 -- .../handling-get-post-requests.mdx | 7 +- .../advanced-features/management-canister.mdx | 36 +++++++-- .../advanced-features/periodic-tasks.mdx | 10 ++- .../advanced-features/randomness.mdx | 20 +---- .../serving-http-request.mdx | 18 +---- .../advanced-features/time-and-timestamps.mdx | 11 ++- .../smart-contracts/call/arguments.mdx | 77 ++++++++++++++++++- .../smart-contracts/call/overview.mdx | 26 +++++-- 9 files changed, 151 insertions(+), 61 deletions(-) diff --git a/docs/developer-docs/getting-started/default-template.mdx b/docs/developer-docs/getting-started/default-template.mdx index 10c7314fb2..274197cbd0 100644 --- a/docs/developer-docs/getting-started/default-template.mdx +++ b/docs/developer-docs/getting-started/default-template.mdx @@ -82,22 +82,15 @@ hello/ hello/ ├── README.md # Default project documentation ├── dfx.json # Project configuration file -├── env.d.ts -├── jest.config.js ├── node_modules ├── package-lock.json # Libraries for frontend development ├── package.json ├── src # Source files directory │   ├── hello_backend | | └── index.ts -│   ├── declarations │   ├── hello_frontend │   │   ├── index.html │   │   └── index.ts -├── test -│   ├── pretest.ts -│   ├── test.ts -│   └── tests.ts └── tsconfig.json ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx index 4a4cfa119a..30458e3c82 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/handling-get-post-requests.mdx @@ -129,10 +129,7 @@ export default class { body: [], transform: [ { - function: [id(), 'xkcdTransform'] as [ - Principal, - string - ], + function: [id(), 'xkcdTransform'], context: Uint8Array.from([]) } ] @@ -366,7 +363,7 @@ export default class { record { url = "https://xkcd.com/642/info.0.json"; max_response_bytes = 2_000 : nat64; - method = variant { get }; + method = variant { post }; headers = vec {}; body = null; transform = record { function = func "${id().toString()}".xkcdTransform; context = vec {} }; diff --git a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx index 16e3e45662..51bdcd00d9 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx @@ -84,14 +84,40 @@ async fn install_code(canister_id: CanisterId, wasm_module: Vec) { }> ```typescript -@update([], CreateCanisterResult) -async executeCreateCanister(): Promise { - const createCanisterResult = await createCanister(); +import { call, IDL, Principal, query, update } from 'azle'; +import { + CanisterInfoArgs, + CreateCanisterArgs, + CreateCanisterResult, +} from 'azle/canisters/management'; + +type State = { + createdCanisterId: Principal; +}; + +let state: State = { + createdCanisterId: Principal.fromText('aaaaa-aa') +}; - state.createdCanisterId = createCanisterResult.canister_id; +export default class { + @update([], CreateCanisterResult) + async executeCreateCanister(): Promise { + const createCanisterResult = await createCanister(); - return createCanisterResult; + state.createdCanisterId = createCanisterResult.canister_id; + + return createCanisterResult; + } +} +async function createCanister(): Promise { +return await call('aaaaa-aa', 'create_canister', { + paramIdlTypes: [CreateCanisterArgs], + returnIdlType: CreateCanisterResult, + args: [{ settings: [], sender_canister_version: [] }], + payment: 50_000_000_000_000n +}); } + ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx index a04a4a15f5..d52fb9a57a 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx @@ -101,7 +101,15 @@ fn post_upgrade() { }> ```typescript -const timerId = setTimer(1_000, () => console.log('timer callback called')); + +import { + IDL, update, setTimer, +} from 'azle'; + +export default class { + @update([IDL.Nat64]) + const timerId = setTimer(1_000, () => console.log('timer callback called')); +}, ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx index 1032480364..86bfd7d0c3 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx @@ -61,25 +61,13 @@ let (randomBytes,): (Vec,) = ic_cdk::api::call(Principal.management_canister }> ```typescript -import { IDL, postUpgrade, query, update } from 'azle'; - -let redeployed = false; +import { IDL, query, update } from 'azle'; export default class { - @postUpgrade([]) - postUpgrade(): void { - redeployed = true; - } - - @query([], IDL.Bool) - getRedeployed(): boolean { - return redeployed; - } - @update([], IDL.Float64) - randomNumber(): number { - return Math.random(); - } + await call('aaaaa-aa', 'raw_rand', { + returnIdlType: IDL.Vec(IDL.Nat8) +}); } ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx index e69feaba65..64b12ed18b 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/serving-http-request.mdx @@ -113,16 +113,6 @@ fn http_request(req: HttpRequest) -> HttpResponse { }> -To serve HTTP requests, you can use the Azle `http-server` functionality by creating a new project with the flag `--http-server`: - -``` -npx azle new http_requests --http-server -cd http_requests -``` - -Then, use the `fetch` functionality to create an HTTP server that can process incoming requests: - - ```typescript import { blob, @@ -157,7 +147,7 @@ const HttpRequest = Record({ }); export default class{ - http_request: @query([HttpRequest], HttpResponse, (req) => { + @query([HttpRequest], HttpResponse, (req) => { const path = req.url.pathname; if(path == "/hello") { return { @@ -170,12 +160,10 @@ export default class{ headers: []; status_code:404; } - } -}); + }), +}; ``` -To learn more about serving an HTTP request in Typescript, refer to [the Azle book reference on fetch](https://demergent-labs.github.io/azle/fetch.html). - }> diff --git a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx index 8f92226bf2..62cd755ed4 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/time-and-timestamps.mdx @@ -52,13 +52,16 @@ let current_time = IC_API::time(); }> ```typescript -@query([], IDL.Nat64) -time(): bigint { - return time(); +import { IDL, query, time } from 'azle'; + +export default class { + @query([], IDL.Nat64) + time(): bigint { + return time(); + } } ``` - }> diff --git a/docs/developer-docs/smart-contracts/call/arguments.mdx b/docs/developer-docs/smart-contracts/call/arguments.mdx index 5110c43092..6e6a5642e6 100644 --- a/docs/developer-docs/smart-contracts/call/arguments.mdx +++ b/docs/developer-docs/smart-contracts/call/arguments.mdx @@ -69,7 +69,7 @@ fn get_numbers(numbers: Vec) -> Vec { }> -Azle refers to the `Vec` type to represent the equivalent of an `array` in Typescript. This is because `Vec` aligns with the [Candid](/docs/current/developer-docs/smart-contracts/candid/candid-concepts) type. +Azle refers to the `Vec` type to represent the equivalent of an `array` in TypeScript. This is because `Vec` aligns with the [Candid](/docs/current/developer-docs/smart-contracts/candid/candid-concepts) type. ```typescript import { IDL, query } from 'azle'; @@ -194,11 +194,86 @@ fn get_text(d: Day) -> &'static str { }> ```typescript +import { IDL } from 'azle'; + export const ReactionType = IDL.Variant({ Fire: IDL.Null, ThumbsUp: IDL.Null, ThumbsDown: IDL.Null }); +export type ReactionType = + | { Fire: null } + | { ThumbsUp: null } + | { ThumbsDown: null }; + +export const User = IDL.Rec(); +export const Post = IDL.Rec(); +export const Thread = IDL.Rec(); +export const Reaction = IDL.Rec(); + +User.fill( + IDL.Record({ + id: IDL.Text, + posts: IDL.Vec(Post), + reactions: IDL.Vec(Reaction), + threads: IDL.Vec(Thread), + username: IDL.Text + }) +); +export type User = { + id: string; + posts: Post[]; + reactions: Reaction[]; + threads: Thread[]; + username: string; +}; + +Post.fill( + IDL.Record({ + id: IDL.Text, + author: User, + reactions: IDL.Vec(Reaction), + text: IDL.Text, + thread: Thread + }) +); +export type Post = { + id: string; + author: User; + reactions: Reaction[]; + text: string; + thread: Thread; +}; + +Thread.fill( + IDL.Record({ + id: IDL.Text, + author: User, + posts: IDL.Vec(Post), + title: IDL.Text + }) +); +export type Thread = { + id: string; + author: User; + posts: Post[]; + title: string; +}; + +Reaction.fill( + IDL.Record({ + id: IDL.Text, + author: User, + post: Post, + reactionType: ReactionType + }) +); +export type Reaction = { + id: string; + author: User; + post: Post; + reactionType: ReactionType; +}; ``` To learn more about variants in Typescript via Azle, refer to [the Azle code](https://github.com/demergent-labs/azle/blob/main/tests/end_to_end/candid_rpc/class_syntax/complex_types/src/candid_types.ts#L3). diff --git a/docs/developer-docs/smart-contracts/call/overview.mdx b/docs/developer-docs/smart-contracts/call/overview.mdx index 9c8ac41ee7..24fb7941d5 100644 --- a/docs/developer-docs/smart-contracts/call/overview.mdx +++ b/docs/developer-docs/smart-contracts/call/overview.mdx @@ -59,11 +59,17 @@ fn increment() { }> ```typescript -incrementCount: update([], nat64, () => { - count += 1n; - return count; -}) +import { update } from 'azle'; + +export default class { + @update + incrementCount: update([], nat64, () => { + count += 1n; + + return count; + }) +}, ``` @@ -120,9 +126,15 @@ fn greet(name: String) -> String { }> ```typescript -readCount: query([], nat64, () => { - return count; -}), + +import { query } from 'azle'; + +export default class { + @query + readCount: query([], nat64, () => { + return count; + }), +} ``` From ffc995f6b4ab0478885141811292f66bfd612463 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Fri, 2 Aug 2024 10:39:45 -0500 Subject: [PATCH 10/13] apply code review revisions --- .../advanced-features/management-canister.mdx | 26 +- .../advanced-features/periodic-tasks.mdx | 17 +- .../advanced-features/randomness.mdx | 13 +- .../smart-contracts/call/arguments.mdx | 233 ++++-------------- .../smart-contracts/call/overview.mdx | 30 +-- 5 files changed, 83 insertions(+), 236 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx index 51bdcd00d9..7a12d310a4 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx @@ -91,33 +91,21 @@ import { CreateCanisterResult, } from 'azle/canisters/management'; -type State = { - createdCanisterId: Principal; -}; - -let state: State = { - createdCanisterId: Principal.fromText('aaaaa-aa') -}; - export default class { @update([], CreateCanisterResult) - async executeCreateCanister(): Promise { const createCanisterResult = await createCanister(); - - state.createdCanisterId = createCanisterResult.canister_id; - + async executeCreateCanister(): Promise { + return await call('aaaaa-aa', 'create_canister', { + paramIdlTypes: [CreateCanisterArgs], + returnIdlType: CreateCanisterResult, + args: [{ settings: [], sender_canister_version: [] }], + payment: 50_000_000_000_000n + }); return createCanisterResult; } } async function createCanister(): Promise { -return await call('aaaaa-aa', 'create_canister', { - paramIdlTypes: [CreateCanisterArgs], - returnIdlType: CreateCanisterResult, - args: [{ settings: [], sender_canister_version: [] }], - payment: 50_000_000_000_000n -}); } - ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx index d52fb9a57a..250cfb7e1e 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/periodic-tasks.mdx @@ -101,15 +101,18 @@ fn post_upgrade() { }> ```typescript - -import { - IDL, update, setTimer, -} from 'azle'; +import { IDL, setTimer, update } from 'azle'; export default class { - @update([IDL.Nat64]) - const timerId = setTimer(1_000, () => console.log('timer callback called')); -}, + @update([], IDL.Nat64) + createTimer(): bigint { + const timerId = setTimer(1_000n, () => + console.log('timer callback called') + ); + + return timerId; + } +} ``` diff --git a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx index 86bfd7d0c3..d0e93ee117 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx @@ -61,13 +61,16 @@ let (randomBytes,): (Vec,) = ic_cdk::api::call(Principal.management_canister }> ```typescript -import { IDL, query, update } from 'azle'; +import { IDL, update } from 'azle'; export default class { - @update([], IDL.Float64) - await call('aaaaa-aa', 'raw_rand', { - returnIdlType: IDL.Vec(IDL.Nat8) -}); + @update([], IDL.Nat64) + createRand(): bigint { + randomInt = await call('aaaaa-aa', 'raw_rand', { returnIdlType: IDL.Vec(IDL.Nat8) + }); + + return randomInt; + } } ``` diff --git a/docs/developer-docs/smart-contracts/call/arguments.mdx b/docs/developer-docs/smart-contracts/call/arguments.mdx index 6e6a5642e6..c82ff73847 100644 --- a/docs/developer-docs/smart-contracts/call/arguments.mdx +++ b/docs/developer-docs/smart-contracts/call/arguments.mdx @@ -74,207 +74,58 @@ Azle refers to the `Vec` type to represent the equivalent of an `array` in TypeS ```typescript import { IDL, query } from 'azle'; -export default class { - @query([], IDL.Vec(IDL.Nat8)) - getBlob(): Uint8Array { - return stringToBlob('hello'); - } - - @query([], IDL.Vec(IDL.Vec(IDL.Nat8))) - getBlobs(): Uint8Array[] { - return [stringToBlob('hello'), stringToBlob('world')]; - } -} - -function stringToBlob(string: string): Uint8Array { - return Buffer.from(string); -} -``` - - -To learn more about the `Vec` object in Typescript via Azle, refer to [the Azle documentation](https://demergent-labs.github.io/azle/). - - - -}> - -Kybra refers to the `Vec` type to represent the equivalent of an `array` in Python. This is because `Vec` aligns with the Candid type. - -```python -from kybra import int32, query, Vec -numbers = [0, 1, 2, 3] -@query -def get_numbers(Vec[int32]) -> Vec[int32]: - return numbers -``` - - -To learn more about `Vec` in Python via Kybra, refer to [the Kybra book reference on Vec](https://demergent-labs.github.io/kybra/reference/candid/vec.html). - - - - - -You can pass a vector as an argument by explicitly specifying the canister name and method name using the `dfx` tool in the following format: - -```bash - dfx canister call canister_name method_name '(vec {})' -``` -Assuming you have a method named `get_numbers` that accepts a `Vec` parameter, as exemplified in other examples: - -```bash - dfx canister call canister_name get_numbers '(vec {1; 2; 3})' -``` -To learn more about calling a method from a canister in bash, refer to the dfx reference on the [dfx canister call command](/docs/current/developer-docs/developer-tools/cli-tools/cli-reference/dfx-canister#dfx-canister-call). - -For additional examples, refer to [type `vec` in the Candid Reference](/docs/current/references/candid-ref#type-vec-t). - - - - -## Variants +const Day = IDL.Variant({ + Sun: IDL.Text, + Mon: IDL.Text, + Tue: IDL.Text, + Wed: IDL.Text, + Thu: IDL.Text, + Fri: IDL.Text, + Sat: IDL.Text +}); +type Day = + | { Sun: string } + | { Mon: string } + | { Tue: string } + | { Wed: string } + | { Thu: string } + | { Fri: string } + | { Sat: string }; -A `variant` type represents a value that is from exactly one of the given cases, or **tags**. Similar to enums, they let you differentiate between different types within the same variable. +export default class { + @query([Day], IDL.Text) + getText(day: Day): string { + if ('Sun' in day) { + return day.Sun; + } -The following example defines a `Day` type representing a day of the week. It utilizes a switch statement to match the input `Day` with one of its variants, returning the corresponding full name of the day. + if ('Mon' in day) { + return day.Mon; + } - - - -```motoko -type Day = {#sun; #mon; #tue; #wed; #thu; #fri; #sat}; - -public query func get_text(d : Day) : Text { - switch d { - case (#sun) "Sunday"; - case (#mon) "Monday"; - case (#tue) "Tuesday"; - case (#wed) "Wednesday"; - case (#thu) "Thursday"; - case (#fri) "Friday"; - case (#sat) "Saturday"; - }; -}; -``` -For additional examples, refer to the [Type variant reference in Motoko](/docs/current/motoko/main/getting-started/motoko-introduction/#variants). + if ('Tue' in day) { + return day.Tue; + } -To learn more about variants in Motoko, refer to Kai Peacock's blog on [using Motoko variants](https://kyle-peacock.com/blog/motoko/using-variants/#:~:text=Motoko%20variants%20are%20a%20cool,storing%2C%20similar%20to%20an%20enum.). + if ('Wed' in day) { + return day.Wed; + } - + if ('Thu' in day) { + return day.Thu; + } - + if ('Fri' in day) { + return day.Fri; + } -```rust -type Day = variant { - Sun; - Mon; - Tue; - Wed; - Thu; - Fri; - Sat; -} + if ('Sat' in day) { + return day.Sat; + } -[query] -fn get_text(d: Day) -> &'static str { - match d { - Day::Sun => "Sunday", - Day::Mon => "Monday", - Day::Tue => "Tuesday", - Day::Wed => "Wednesday", - Day::Thu => "Thursday", - Day::Fri => "Friday", - Day::Sat => "Saturday", + throw new Error(`Variant "Day" has unknown tag`); } } -``` - - - -}> - -```typescript -import { IDL } from 'azle'; - -export const ReactionType = IDL.Variant({ - Fire: IDL.Null, - ThumbsUp: IDL.Null, - ThumbsDown: IDL.Null -}); -export type ReactionType = - | { Fire: null } - | { ThumbsUp: null } - | { ThumbsDown: null }; - -export const User = IDL.Rec(); -export const Post = IDL.Rec(); -export const Thread = IDL.Rec(); -export const Reaction = IDL.Rec(); - -User.fill( - IDL.Record({ - id: IDL.Text, - posts: IDL.Vec(Post), - reactions: IDL.Vec(Reaction), - threads: IDL.Vec(Thread), - username: IDL.Text - }) -); -export type User = { - id: string; - posts: Post[]; - reactions: Reaction[]; - threads: Thread[]; - username: string; -}; - -Post.fill( - IDL.Record({ - id: IDL.Text, - author: User, - reactions: IDL.Vec(Reaction), - text: IDL.Text, - thread: Thread - }) -); -export type Post = { - id: string; - author: User; - reactions: Reaction[]; - text: string; - thread: Thread; -}; - -Thread.fill( - IDL.Record({ - id: IDL.Text, - author: User, - posts: IDL.Vec(Post), - title: IDL.Text - }) -); -export type Thread = { - id: string; - author: User; - posts: Post[]; - title: string; -}; - -Reaction.fill( - IDL.Record({ - id: IDL.Text, - author: User, - post: Post, - reactionType: ReactionType - }) -); -export type Reaction = { - id: string; - author: User; - post: Post; - reactionType: ReactionType; -}; - ``` To learn more about variants in Typescript via Azle, refer to [the Azle code](https://github.com/demergent-labs/azle/blob/main/tests/end_to_end/candid_rpc/class_syntax/complex_types/src/candid_types.ts#L3). diff --git a/docs/developer-docs/smart-contracts/call/overview.mdx b/docs/developer-docs/smart-contracts/call/overview.mdx index 24fb7941d5..a4958d8842 100644 --- a/docs/developer-docs/smart-contracts/call/overview.mdx +++ b/docs/developer-docs/smart-contracts/call/overview.mdx @@ -59,17 +59,18 @@ fn increment() { }> ```typescript - -import { update } from 'azle'; +import { IDL, update } from 'azle'; export default class { - @update - incrementCount: update([], nat64, () => { - count += 1n; + count: bigint = 0n; + + @update([], IDL.Nat64) + incrementCount(): bigint { + this.count += 1n; - return count; - }) -}, + return this.count; + } +} ``` @@ -126,14 +127,15 @@ fn greet(name: String) -> String { }> ```typescript - -import { query } from 'azle'; +import { IDL, query } from 'azle'; export default class { - @query - readCount: query([], nat64, () => { - return count; - }), + count: bigint = 0n; + + @query([], IDL.Nat64) + readCount(): bigint { + return this.count; + } } ``` From 7f52f4355c654f57a5a97d9b9f9417183cd2eb53 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon <133128541+jessiemongeon1@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:06:38 -0500 Subject: [PATCH 11/13] Update management-canister.mdx --- .../advanced-features/management-canister.mdx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx index 7a12d310a4..61a5ed06ef 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/management-canister.mdx @@ -84,28 +84,23 @@ async fn install_code(canister_id: CanisterId, wasm_module: Vec) { }> ```typescript -import { call, IDL, Principal, query, update } from 'azle'; +import { call, update } from 'azle'; import { - CanisterInfoArgs, CreateCanisterArgs, - CreateCanisterResult, + CreateCanisterResult } from 'azle/canisters/management'; export default class { @update([], CreateCanisterResult) - const createCanisterResult = await createCanister(); - async executeCreateCanister(): Promise { - return await call('aaaaa-aa', 'create_canister', { + async executeCreateCanister(): Promise { + return await call('aaaaa-aa', 'create_canister', { paramIdlTypes: [CreateCanisterArgs], returnIdlType: CreateCanisterResult, args: [{ settings: [], sender_canister_version: [] }], payment: 50_000_000_000_000n }); - return createCanisterResult; } } -async function createCanister(): Promise { -} ``` From 0935bf7021fa1b632a1c160a0373f4c11343c92e Mon Sep 17 00:00:00 2001 From: Jessie Mongeon <133128541+jessiemongeon1@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:07:23 -0500 Subject: [PATCH 12/13] Update randomness.mdx --- .../smart-contracts/advanced-features/randomness.mdx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx index d0e93ee117..ea5395fe14 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx @@ -61,15 +61,16 @@ let (randomBytes,): (Vec,) = ic_cdk::api::call(Principal.management_canister }> ```typescript -import { IDL, update } from 'azle'; +import { call, IDL, update } from 'azle'; export default class { @update([], IDL.Nat64) - createRand(): bigint { - randomInt = await call('aaaaa-aa', 'raw_rand', { returnIdlType: IDL.Vec(IDL.Nat8) - }); + async createRand(): Promise { + const randomInt = await call('aaaaa-aa', 'raw_rand', { + returnIdlType: IDL.Vec(IDL.Nat8) + }); - return randomInt; + return randomInt; } } ``` From ff809334e7f9a00b7f1ddd338b8b91eb02ea205a Mon Sep 17 00:00:00 2001 From: Jessie Mongeon <133128541+jessiemongeon1@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:23:11 -0500 Subject: [PATCH 13/13] Update randomness.mdx --- .../smart-contracts/advanced-features/randomness.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx index ea5395fe14..c202438857 100644 --- a/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx +++ b/docs/developer-docs/smart-contracts/advanced-features/randomness.mdx @@ -64,13 +64,13 @@ let (randomBytes,): (Vec,) = ic_cdk::api::call(Principal.management_canister import { call, IDL, update } from 'azle'; export default class { - @update([], IDL.Nat64) - async createRand(): Promise { - const randomInt = await call('aaaaa-aa', 'raw_rand', { + @update([], IDL.Vec(IDL.Nat8)) + async randomBytes(): Promise { + const bytes: Uint8Array = await call('aaaaa-aa', 'raw_rand', { returnIdlType: IDL.Vec(IDL.Nat8) }); - return randomInt; + return bytes; } } ```