diff --git a/content/docs/example-trigger.md b/content/docs/example-trigger.md new file mode 100644 index 0000000..94191f0 --- /dev/null +++ b/content/docs/example-trigger.md @@ -0,0 +1,171 @@ +--- +description: 'Integrate task triggers directly inside on-chain contracts' +sidebar: 'docs' +prev: '/docs/' +next: '/docs/trigger-monitoring/' +--- + +# Example: Trigger + +First off -- why you would want this? +In certain situations all that is needed is a simple task being scheduled by a person, that is easily managed checking on its progress every so often. + +A more advanced use would be to integrate logic for scheduling directly inside the contracts functionality, such that the contract can schedule and maintain a task. This effectively allows a contract to have a fully autonomous runtime, a decentralized automonous business appears! So, if you would like to integrate cron within a contract, here's the full CRUD example with all the cases for interacting directly. Bonus points for setting this up with a DAO :) + +# Example: Cross-Crontract Cron Task Management + +[View Full Source](https://github.com/Cron-Near/contracts/tree/main/examples/cross-contract) + +This example shows how to setup a cross-contract implementation with croncat. The demo functionality shows an on-chain indexing of balances in a time series format. This contract allows scheduling, updating, removing & checking status. + +## Contract Setup + +Integration in a cross-contract setup requires 3 main things: +1. ABI Definitions +2. Methods to schedule +3. Methods to maintain + +## Definitions: + +You will need the following definitions for rust to be able to analyze and structure you code properly. + +```rust + +#[derive(BorshDeserialize, BorshSerialize, Debug, Serialize, Deserialize, PartialEq)] +#[serde(crate = "near_sdk::serde")] +pub struct Task { + pub owner_id: AccountId, + pub contract_id: AccountId, + pub function_id: String, + pub cadence: String, + pub recurring: bool, + pub total_deposit: U128, + pub deposit: U128, + pub gas: Gas, + pub arguments: Vec, +} + +#[ext_contract(ext_croncat)] +pub trait ExtCroncat { + fn get_tasks(&self, offset: Option) -> (Vec, U128); + fn get_all_tasks(&self, slot: Option) -> Vec; + fn get_task(&self, task_hash: Base64VecU8) -> Task; + fn create_task( + &mut self, + contract_id: String, + function_id: String, + cadence: String, + recurring: Option, + deposit: Option, + gas: Option, + arguments: Option>, + ) -> Base64VecU8; + fn update_task( + &mut self, + task_hash: Base64VecU8, + cadence: Option, + recurring: Option, + deposit: Option, + gas: Option, + arguments: Option>, + ); + fn remove_task(&mut self, task_hash: Base64VecU8); + fn proxy_call(&mut self); +} +``` + +## Scheduling + +Setting up a single or recurring task is very straightforward, however it can be hard to guess at the right parameters. The following is an example setup for a task the will execute a transaction to the account `crosscontract.testnet` using the method `tick` (which computes a timeseries tick) at an interveral of every 1 minute. + +Key things to note: +* There is a callback shown here, it is a way to get the task hash, the main identifier for your scheduled task. +* attached deposit is used to fund the future task executions +* Parameters in this example will vary from your implementation, this is just a sample. + +```rust +/// Create a new scheduled task, registering the "tick" method with croncat +/// +/// ```bash +/// near call crosscontract.testnet schedule '{ "function_id": "tick", "period": "0 */1 * * * *" }' --accountId YOUR_ACCOUNT.testnet +/// ``` +#[payable] +pub fn schedule(&mut self, function_id: String, period: String) -> Promise { + assert_eq!( + env::current_account_id(), + env::predecessor_account_id(), + "{}", + ERR_ONLY_OWNER + ); + // NOTE: Could check that the balance supplied is enough to cover XX task calls. + + ext_croncat::create_task( + env::current_account_id(), + function_id, + period, + Some(true), + Some(U128::from(NO_DEPOSIT)), + Some(GAS_FOR_TICK_CALL), // 30 Tgas + None, + &self.cron.clone().expect(ERR_NO_CRON_CONFIGURED), + env::attached_deposit(), + GAS_FOR_SCHEDULE_CALL, + ) + .then(ext::schedule_callback( + &env::current_account_id(), + NO_DEPOSIT, + GAS_FOR_SCHEDULE_CALLBACK, + )) +} + +/// Get the task hash, and store in state +#[private] +pub fn schedule_callback(&mut self, #[callback] task_hash: Base64VecU8) { + log!("schedule_callback task_hash {:?}", &task_hash); + self.task_hash = Some(task_hash); +} +``` + +## Maintaining the Task + +Once you've scheduled a task, its important to make sure it is funded to continue running (if your app needs it). The task hash allows you to update or get information about your task. Your contract can then know key information like how much balance is remaining on the task itself. + +For a full sample of updating, removing & more: [View Full Demo Source](https://github.com/Cron-Near/contracts/tree/main/examples/cross-contract) + +```rust +/// Get the task status, including remaining balance & etc. +/// Useful for automated on-chain task management! This method could be scheduled as well, and manage re-funding tasks or changing tasks on new data. +/// +/// ```bash +/// near call crosscontract.testnet status +/// ``` +pub fn status(&self) -> Promise { + // TODO: fix this! serialization is not working + let hash = self.task_hash.clone().expect(ERR_NO_TASK_CONFIGURED); + log!("TASK HASH: {:?} {:?} {}", &hash, serde_json::to_string(&hash).unwrap(), serde_json::to_string(&hash).unwrap()); + ext_croncat::get_task( + // hash, + serde_json::to_string(&hash).unwrap().to_string(), + &self.cron.clone().expect(ERR_NO_CRON_CONFIGURED), + NO_DEPOSIT, + GAS_FOR_STATUS_CALL, + ) + .then(ext::schedule_callback( + &env::current_account_id(), + NO_DEPOSIT, + GAS_FOR_STATUS_CALLBACK, + )) +} + +/// Get the task hash, and store in state +/// NOTE: This method helps contract understand remaining task balance, in case more is needed to continue running. +/// NOTE: This could handle things about the task, or have logic about changing the task in some way. +#[private] +pub fn status_callback(&self, #[callback] task: Option) -> Option { + // NOTE: Could check remaining balance here + // NOTE: Could have logic to another callback IF the balance is running low + task +} +``` + +There's a lot of information in this guide, and you've probably got questions. Do not hesitate to reach out and get help with further integrating croncat! \ No newline at end of file diff --git a/content/docs/task-creation.md b/content/docs/task-creation.md index 459e5f7..280eada 100644 --- a/content/docs/task-creation.md +++ b/content/docs/task-creation.md @@ -11,7 +11,7 @@ next: '/docs/task-monitoring/' Croncat tasks follow a very straight forward flow: -1. Deploy or find a contract to a NEAR blockchain +1. Deploy or find a contract to a NEAR blockchain account 2. Decide how often a contract should be called & estimate it's transaction fee needs. 3. Create the task configuration within croncat 4. Monitor the ongoing progress of the task diff --git a/content/docs/trigger-creation.md b/content/docs/trigger-creation.md new file mode 100644 index 0000000..7e09f3c --- /dev/null +++ b/content/docs/trigger-creation.md @@ -0,0 +1,94 @@ +--- +description: 'Create a task in croncat specifying different configuration params' +sidebar: 'docs' +prev: '/docs/' +next: '/docs/trigger-monitoring/' +--- + +# Trigger Creation + +## Basic Flow + +Croncat triggers follow a very straight forward flow: + +1. Create a croncat task - [See here for setup](./task-creation.md) +2. Get the task hash for the task you own & want to trigger +3. Create the trigger with croncat +4. Monitor the ongoing progress of the trigger + +## Configuration Reference + +Each field within croncat serves a specific purpose, the following details show what kinds of data are acceptable. [View Source](https://github.com/CronCats/contracts/blob/main/manager/src/triggers.rs#L52-L55) + +| Field | Type | Description | +| ------- | ------- | ------- | +| contract_id | AccountId | Account to direct all execution calls against | +| function_id | String | Contract method this task will be executing | +| task_hash | String | The hash of the task you own and want to trigger | +| arguments | Vec | NOTE: Only allow static pre-defined bytes, most useful for cross-contract task creation | +| | | | + +## Simple Trigger Creation Example + +Let's say you have a task that calls the contract "counter" that increments a storage integer. You want it to trigger every even minute by using a different contract that returns true/false before calling the increment contract. + +Creating a trigger will look like this: + +```bash +near call manager_v1.croncat.testnet create_trigger '{"contract_id": "view.in.testnet","function_id": "get_a_boolean","arguments":"","task_hash":"fsda1234fdas1234..."}' --accountId YOU.testnet +``` + +Now let's break this down a bit: + +First snippet makes a call request to the "cron" manager in testnet to register a new trigger. +```bash +near call manager_v1.croncat.testnet create_trigger +``` + +Next we specify the contract and function getting viewed, like this: +```bash +'{"contract_id": "view.in.testnet","function_id": "get_a_boolean", +``` + +Then we specify the `task_hash` of this contract call: +```bash +"arguments":"","task_hash":"fsda1234fdas1234...", +``` + +This is completed by making sure the transaction is signed by the account that will own this trigger: +```bash +--accountId YOUR_NEAR_ACCT.testnet +``` + +**Important thing to note:** You will get a trigger hash upon successful creation. Save this hash as its your access to monitor and update the trigger in the future. + + +## How to get Trigger Hash + +```bash +near view get_hash '{"contract_id": "","function_id": "","cadence": "0 0 * * * *","owner_id": ""}' +``` + +Example (get Task Hash from "ping" function): +```bash +near view manager_v1.croncat.testnet get_hash '{"contract_id": "jakson.pool.f863973.m0","function_id": "ping","cadence": "0 0 * * * *","owner_id": "jakson.testnet"}' +``` + +## Remove task + +When deleting a task, all unused balance will be returned to the wallet of the task owner. + + +```bash +near call remove_task '{"task_hash": "r2JvrGPvDkFUuqdF4x1+L93aYKGmgp4GqXT4UAK3AE4="}' --accountId jakson.testnet +``` + +Example + +```bash +near call manager_v1.croncat.testnet remove_task '{"task_hash": "r2JvrGPvDkFUuqdF4x1"}' --accountId +``` + +## More Examples + +For deeper examples of contracts & task creation, [view all examples here](/docs/examples). diff --git a/content/docs/trigger-integration.md b/content/docs/trigger-integration.md new file mode 100644 index 0000000..e938516 --- /dev/null +++ b/content/docs/trigger-integration.md @@ -0,0 +1,164 @@ +--- +description: 'Integrate task triggers directly inside on-chain contracts' +sidebar: 'docs' +prev: '/docs/' +next: '/docs/trigger-monitoring/' +--- + +# Trigger Integration + +This example shows how to setup a cross-contract implementation with croncat. The demo functionality shows an on-chain indexing of balances in a time series format. This contract allows scheduling, updating, removing & checking status. + +## Contract Setup + +[View Full Source](https://github.com/Cron-Near/contracts/tree/main/examples/views) + +Integration in a cross-contract setup requires 3 main things: +1. ABI Definitions +2. Methods to schedule +3. Methods to maintain + +## Definitions: + +You will need the following definitions for rust to be able to analyze and structure you code properly. + +```rust + +#[derive(BorshDeserialize, BorshSerialize, Debug, Serialize, Deserialize, PartialEq)] +#[serde(crate = "near_sdk::serde")] +pub struct Task { + pub owner_id: AccountId, + pub contract_id: AccountId, + pub function_id: String, + pub cadence: String, + pub recurring: bool, + pub total_deposit: U128, + pub deposit: U128, + pub gas: Gas, + pub arguments: Vec, +} + +#[ext_contract(ext_croncat)] +pub trait ExtCroncat { + fn get_tasks(&self, offset: Option) -> (Vec, U128); + fn get_all_tasks(&self, slot: Option) -> Vec; + fn get_task(&self, task_hash: Base64VecU8) -> Task; + fn create_task( + &mut self, + contract_id: String, + function_id: String, + cadence: String, + recurring: Option, + deposit: Option, + gas: Option, + arguments: Option>, + ) -> Base64VecU8; + fn update_task( + &mut self, + task_hash: Base64VecU8, + cadence: Option, + recurring: Option, + deposit: Option, + gas: Option, + arguments: Option>, + ); + fn remove_task(&mut self, task_hash: Base64VecU8); + fn proxy_call(&mut self); +} +``` + +## Scheduling + +Setting up a single or recurring task is very straightforward, however it can be hard to guess at the right parameters. The following is an example setup for a task the will execute a transaction to the account `crosscontract.testnet` using the method `tick` (which computes a timeseries tick) at an interveral of every 1 minute. + +Key things to note: +* There is a callback shown here, it is a way to get the task hash, the main identifier for your scheduled task. +* attached deposit is used to fund the future task executions +* Parameters in this example will vary from your implementation, this is just a sample. + +```rust +/// Create a new scheduled task, registering the "tick" method with croncat +/// +/// ```bash +/// near call crosscontract.testnet schedule '{ "function_id": "tick", "period": "0 */1 * * * *" }' --accountId YOUR_ACCOUNT.testnet +/// ``` +#[payable] +pub fn schedule(&mut self, function_id: String, period: String) -> Promise { + assert_eq!( + env::current_account_id(), + env::predecessor_account_id(), + "{}", + ERR_ONLY_OWNER + ); + // NOTE: Could check that the balance supplied is enough to cover XX task calls. + + ext_croncat::create_task( + env::current_account_id(), + function_id, + period, + Some(true), + Some(U128::from(NO_DEPOSIT)), + Some(GAS_FOR_TICK_CALL), // 30 Tgas + None, + &self.cron.clone().expect(ERR_NO_CRON_CONFIGURED), + env::attached_deposit(), + GAS_FOR_SCHEDULE_CALL, + ) + .then(ext::schedule_callback( + &env::current_account_id(), + NO_DEPOSIT, + GAS_FOR_SCHEDULE_CALLBACK, + )) +} + +/// Get the task hash, and store in state +#[private] +pub fn schedule_callback(&mut self, #[callback] task_hash: Base64VecU8) { + log!("schedule_callback task_hash {:?}", &task_hash); + self.task_hash = Some(task_hash); +} +``` + +## Maintaining the Task + +Once you've scheduled a task, its important to make sure it is funded to continue running (if your app needs it). The task hash allows you to update or get information about your task. Your contract can then know key information like how much balance is remaining on the task itself. + +For a full sample of updating, removing & more: [View Full Demo Source](https://github.com/Cron-Near/contracts/tree/main/examples/cross-contract) + +```rust +/// Get the task status, including remaining balance & etc. +/// Useful for automated on-chain task management! This method could be scheduled as well, and manage re-funding tasks or changing tasks on new data. +/// +/// ```bash +/// near call crosscontract.testnet status +/// ``` +pub fn status(&self) -> Promise { + // TODO: fix this! serialization is not working + let hash = self.task_hash.clone().expect(ERR_NO_TASK_CONFIGURED); + log!("TASK HASH: {:?} {:?} {}", &hash, serde_json::to_string(&hash).unwrap(), serde_json::to_string(&hash).unwrap()); + ext_croncat::get_task( + // hash, + serde_json::to_string(&hash).unwrap().to_string(), + &self.cron.clone().expect(ERR_NO_CRON_CONFIGURED), + NO_DEPOSIT, + GAS_FOR_STATUS_CALL, + ) + .then(ext::schedule_callback( + &env::current_account_id(), + NO_DEPOSIT, + GAS_FOR_STATUS_CALLBACK, + )) +} + +/// Get the task hash, and store in state +/// NOTE: This method helps contract understand remaining task balance, in case more is needed to continue running. +/// NOTE: This could handle things about the task, or have logic about changing the task in some way. +#[private] +pub fn status_callback(&self, #[callback] task: Option) -> Option { + // NOTE: Could check remaining balance here + // NOTE: Could have logic to another callback IF the balance is running low + task +} +``` + +There's a lot of information in this guide, and you've probably got questions. Do not hesitate to reach out and get help with further integrating croncat! \ No newline at end of file diff --git a/content/docs/trigger-monitoring.md b/content/docs/trigger-monitoring.md new file mode 100644 index 0000000..fef4e02 --- /dev/null +++ b/content/docs/trigger-monitoring.md @@ -0,0 +1,29 @@ +--- +description: 'Watch tasks in croncat and access configuration' +sidebar: 'docs' +prev: '/docs/trigger-creation/' +next: '/docs/trigger-integration/' +--- + +# Trigger Monitoring + +There are two ways to view tasks: + +* [Croncat Website](https://cron.cat/tasks) +* Croncat CLI + +The website is the easiest for quickly viewing all active tasks, however not as helpful for understanding your task directly. + +Using the CLI, you can access a task directly, however it will require a hash of the task. You obtain the hash at the creation of each task (as noted in [task creation](/docs/task-creation)). + +Once you have a task hash, you can use the following command to retrieve the current status and other configurations: + +```bash +croncat task r2JvrGPvDkFUuqdF4x1+L93aYKGmgp4GqXT4UAK3AE4= +``` + +This is just a shortcut for the method available using near-cli as well: + +```bash +near view manager_v1.croncat.testnet get_task '{"task_hash": "r2JvrGPvDkFUuqdF4x1+L93aYKGmgp4GqXT4UAK3AE4="}' +``` \ No newline at end of file diff --git a/gridsome.config.js b/gridsome.config.js index e092b63..d4862bb 100644 --- a/gridsome.config.js +++ b/gridsome.config.js @@ -56,23 +56,33 @@ module.exports = { '/docs/contract-integration/', ], }, + { + title: 'Triggers', + items: [ + '/docs/trigger-creation/', + '/docs/trigger-monitoring/', + '/docs/trigger-integration/', + ], + }, { title: 'Examples', items: [ '/docs/examples/', + '/docs/example-trigger/', '/docs/example-counter/', '/docs/example-charity/', '/docs/example-airdrop/', '/docs/example-indexer/', ], }, - { - title: 'Tutorials', - items: [ - '/docs/tutorials/', - '/docs/tutorials-pixel-pet/', - ], - }, + // Removing tutorials for now, as were moving to recipes + // { + // title: 'Tutorials', + // items: [ + // '/docs/tutorials/', + // '/docs/tutorials-pixel-pet/', + // ], + // }, ], }, ],