# _providers/ollama.mdx import { Callout } from 'nextra-theme-docs' # Ollama Ollama is a free and open-source LLM provider that runs locally, providing an accessible option for processing and validating intelligent contracts within GenLayer. While it may perform slower than other providers, it is set up to run within Docker containers to facilitate the operations. ## Setup during `genlayer init` When you run the `genlayer init` command, you will be prompted to select the LLM providers you want to use. If you choose Ollama, it will automatically set up the necessary Docker containers for running the validators. ### Server Details Ollama server details are typically configured as follows: ```shell OLAMAPROTOCOL=http OLAMAHOST=ollama OLAMAPORT=11434 ``` This environment variable is configured in the `.env` file located in the Studio's root folder. ### Troubleshooting Tips - **Missing Configuration**: Ensure that the Ollama server details (`OLAMAPROTOCOL`, `OLAMAHOST`, `OLAMAPORT`) are set correctly during the initialization process. - **Docker Setup Issues**: Verify that Docker is installed and running on your system, as Ollama relies on Docker containers for its operation. - **Service Status**: To confirm Ollama is running, use the `docker ps` command and check for the `ollama` container. # _providers/openai.mdx # OpenAI OpenAI is an LLM provider that provides fast and reliable AI models used by validators to process and validate Intelligent Contracts. ## Setup during `genlayer init` When you run the `genlayer init` command, you will be prompted to select the LLM providers you want to use. If you choose OpenAI, you will need to provide an [API key](https://openai.com/api/) during the setup process. This key is necessary to authenticate and access OpenAI's services. Set the OpenAI API key when prompted: ```shell OPENAIKEY=your_openai_api_key ``` import { Callout } from 'nextra-theme-docs' This environment variable is configured in the `.env` file located in the Studio's root folder. ### Troubleshooting Tips - **Missing API Key**: Ensure that you enter the `OPENAIKEY` when prompted during the initialization process. - **Incorrect Configuration**: Verify that the API key you entered is valid and that you have selected the correct provider during initialization. # _temp/security-and-best-practices/grey-boxing.mdx # Greyboxing in GenLayer Greyboxing combines elements of both "blackboxing" and "whiteboxing" to create a semi-transparent operational environment for AI models. In GenLayer, this technique involves individually configuring each validator's interaction with AI models, ensuring that manipulative or malicious inputs do not affect the blockchain's integrity. ## How Greyboxing Works 1. **Unique Configuration per Validator**: Each validator in GenLayer operates its AI models within a uniquely configured greybox environment. This customization makes it more difficult for attackers to perform successful universal attacks, as they cannot predict the specific defensive mechanisms employed by each validator. 2. **Input Filtration**: Inputs to AI models are rigorously filtered to remove or sanitize potential threats before processing. This precaution helps ensure that only safe and intended data influences the AI's decision-making processes. 3. **Output Restrictions**: Outputs from AI models are confined within predefined safety parameters to prevent unintended or harmful responses. These restrictions are tailored to each greybox setup, enhancing security and reliability. 4. **Model Isolation**: While AI models access necessary data for operations, they do so within controlled and observable environments. This isolation helps prevent external manipulations and maintains the integrity of model responses. 5. **Continuous Monitoring**: The operations within each greyboxed environment are continuously monitored for any signs of anomalous or potentially harmful activity. This ongoing surveillance allows for immediate detection and response to security threats. # _temp/security-and-best-practices/universal-attacks.mdx # Universal Attacks in GenLayer Universal attacks are a type of adversarial attack where attackers craft inputs that are effective across different models or different runs of the same model. This could involve creating input data that consistently causes models to make errors or behave in unintended ways, regardless of slight variations in model training or deployment environments. The universal nature of these attacks makes them particularly challenging to defend against because they exploit fundamental weaknesses in the models' architecture or training data. ## Mitigating Universal Attacks in GenLayer - **Random Selection of Validators**: Validators are randomly selected to review transactions. Random selection disrupts potential attack planning, as attackers cannot easily predict which validators (and consequently, which models) will be validating any given transaction. - **Greyboxing**: [Greyboxing](/security-and-best-practices/grey-boxing) is used to create a controlled environment where inputs and outputs to AI models are rigorously monitored and filtered. This security layer is customized for each validator, further enhancing the resilience against universal attacks. - **Validator Checks on Leader's Output**: This step acts as a **second perspective**, ensuring that any errors or manipulations in the leader's outputs are likely to be caught by other validators, adding a robust layer of verification that helps maintain the integrity of transaction processing. # about-genlayer/core-concepts/accounts-and-addresses.mdx # Accounts and Addressing ## Overview Accounts are fundamental to interacting with the GenLayer network. They represent users or entities that can hold tokens, deploy Intelligent Contracts, and initiate transactions. ## Types of Accounts 1. **Externally Owned Accounts (EOAs)**: - Controlled by private keys - Can initiate transactions and hold tokens 2. **Contract Accounts**: - Associated with deployed Intelligent Contracts - Have their own addresses and code ## Account Addresses - **Address Format**: GenLayer uses a specific address format, typically represented as a hexadecimal string prefixed with `0x`. - **Public and Private Keys**: Addresses are derived from public keys, which in turn are generated from private keys kept securely by the account owner. ## Interacting with Intelligent Contracts - **Transaction Sending**: Accounts initiate transactions to call functions on Intelligent Contracts or transfer tokens. - **Gas Fees**: Transactions require gas fees to be processed. ## Account Management - **Creating Accounts**: Users can create new accounts using wallets or development tools provided by GenLayer. - **Security Practices**: Users must securely manage their private keys, as losing them can result in loss of access to their funds. # about-genlayer/core-concepts/economic-model.mdx # Economic Model ## Overview GenLayer's economic model is designed to incentivize participants to maintain the network's security and functionality. It involves staking, rewards, transaction fees, and penalties. ## Key Components - **Staking**: Validators must stake tokens to participate in the validation process, aligning their interests with the network's health. - **Rewards**: Validators receive rewards for correctly validating transactions. - **Transaction Fees**: Users pay fees for transaction processing, which are partly used to reward validators. - **Slashing**: Validators acting maliciously or incompetently can have their staked tokens slashed as a penalty. ## Incentive Mechanisms - **Positive Incentives**: Rewards and fees motivate validators to act in the network's best interest. - **Negative Incentives**: Slashing and penalties deter malicious behavior. ## Economic Security - **Stake-Based Security**: The amount staked by validators serves as a deterrent against attacks, as they risk losing their stake. - **Balancing Supply and Demand**: The economic model aims to balance the supply of validation services with demand from users. # about-genlayer/core-concepts/genvm.mdx # GenVM (GenLayer Virtual Machine) GenVM is the execution environment for Intelligent Contracts in the GenLayer protocol. It serves as the backbone for processing and managing contract operations within the GenLayer ecosystem. ## Purpose of GenVM GenVM's only purpose is to execute Intelligent Contracts, which can have non-deterministic code while maintaining blockchain security and consistency. In summary, GenVM plays a crucial role in enabling GenLayer's unique features, bridging the gap between traditional smart contracts and AI-powered, web-connected Intelligent Contracts. ## Key Features That Make GenVM Different Unlike traditional blockchain virtual machines such as Ethereum Virtual Machine (EVM), GenVM has some advanced features. - **Integration with LLMs**: GenVM facilitates seamless interaction between Intelligent Contracts and Large Language Models - **Web access**: GenVM provides access to the internet - **User friendliness**: Intelligent Contracts can be written in Python, which makes the learning curve much more shallow ## How GenVM Works 1. **Contract Deployment**: When an Intelligent Contract is deployed, GenVM compiles and executes the contract code. 2. **Transaction Processing**: As transactions are submitted to the network, GenVM executes the relevant contract functions and produces the contract's next state. ## Developer Considerations When developing Intelligent Contracts for GenVM: - Utilize Python's robust libraries and features - Consider potential non-deterministic outcomes when integrating LLMs - Implement proper error handling for web data access - Optimize code for efficient execution within the rollup environment # about-genlayer/core-concepts/large-language-model-llm-integration.mdx # Large Language Model (LLM) Integration ## Overview Intelligent Contracts in GenLayer can interact directly with Large Language Models (LLMs), enabling natural language processing and more complex decision-making capabilities within blockchain applications. ## Key Features - **Natural Language Understanding**: Contracts can process and interpret instructions written in natural language. - **Dynamic Decision Making**: Utilizing LLMs allows contracts to make context-aware decisions based on complex inputs. ## Implementation 1. **LLM Providers**: Validators are configured with LLM providers (e.g., OpenAI, Ollama) to process LLM requests. 2. **Equivalence Principle**: LLM outputs are validated using the Equivalence Principle to ensure consensus among validators. 3. **Prompt Design**: Developers craft prompts to interact effectively with LLMs, specifying expected formats and constraints. ## Considerations - **Cost and Performance**: LLM interactions may incur additional computational costs and latency. - **Security**: Care must be taken to prevent prompt injections and ensure the reliability of LLM responses. # about-genlayer/core-concepts/non-deterministic-operations-handling.mdx # Non-Deterministic Operations Handling ## Overview GenLayer extends traditional smart contracts by allowing Intelligent Contracts to perform non-deterministic operations, such as interacting with Large Language Models (LLMs) and accessing web data. Handling the variability inherent in these operations is crucial for maintaining consensus across the network. ## Challenges - **Variability of Outputs**: Non-deterministic operations can produce different outputs when executed by different validators. - **Consensus Difficulty**: Achieving consensus on varying outputs requires specialized mechanisms. ## Solutions in GenLayer - **Equivalence Principle**: Validators assess whether different outputs are equivalent based on predefined criteria, allowing for consensus despite variability. - **Optimistic Democracy**: The consensus mechanism accommodates non-deterministic operations by allowing provisional acceptance of transactions and providing an appeals process. ## Developer Considerations - **Defining Equivalence Criteria**: Developers must specify what constitutes equivalent outputs in their Intelligent Contracts. - **Testing and Validation**: Thorough testing is essential to ensure that non-deterministic operations behave as expected in the consensus process. # about-genlayer/core-concepts/optimistic-democracy/appeal-process.mdx # Appeals Process The appeals process in GenLayer is a critical component of the Optimistic Democracy consensus mechanism. It provides a means for correcting errors or disagreements in the validation of Intelligent Contracts. This process ensures that non-deterministic transactions are accurately evaluated, contributing to the robustness and fairness of the platform. ## How It Works - **Initiating an Appeal**: Participants can appeal the initial decision by submitting a request and a required bond during the Finality Window. A new set of validators is then added to the original group to reassess the transaction. - **Appeal Evaluation**: The new validators first review the existing transaction to decide if it needs to be overturned. If they agree it should be re-evaluated, a new leader re-evaluates the transaction. The combined group of original and new validators then review this new evaluation to ensure accuracy. - **Escalating Appeals**: If unresolved, the appeal can escalate, doubling the number of validators each round until a majority consensus is reached or all validators have participated. Once a consensus is reached, the final decision is recorded, and the transaction's state is updated. Correct appellants receive a reward, while those who are incorrect may lose their bond. ## Gas Costs for Appeals The gas costs for an appeal can be covered by the original user, the appellant, or any third party. When submitting a transaction, users can include an optional tip to cover potential appeal costs. If insufficient gas is provided, the appeal may fail to be processed, but any party can supply additional gas to ensure the appeal proceeds. # about-genlayer/core-concepts/optimistic-democracy/equivalence-principle.mdx # Equivalence Principle Mechanism The Equivalence Principle mechanism is a cornerstone in ensuring that Intelligent Contracts function consistently across various validators when handling non-deterministic outputs like responses from Large Language Models (LLMs) or data retrieved through web browsing. It plays a crucial role in how validators assess and agree on the outcomes proposed by the Leader. The Equivalence Principle protects the network from manipulations or errors by ensuring that only suitable, equivalent outcomes influence the blockchain state. ## Key Features of the Equivalence Principle The Equivalence Principle is fundamental to how Intelligent Contracts operate, ensuring they work reliably across different network validators. - **Consistency in Decentralized Outputs:** The Equivalence Principle allows outputs from various sources, such as LLMs or web data, to be different yet still considered valid as long as they meet predefined standards. This is essential to maintain fairness and uniform decision-making across the blockchain, despite the natural differences in AI-generated responses or web-sourced information. - **Security Enhancement:** To protect the integrity of transactions, the Equivalence Principle requires that all validators check each other’s work. This mutual verification helps prevent errors and manipulation, ensuring that only accurate and agreed-upon data affects the blockchain. - **Output Validation Flexibility:** Intelligent Contracts often need to handle complex and varied data. This part of the principle allows developers to set specific rules for what counts as "equivalent" or acceptable outputs. This flexibility helps developers tailor the validation process to suit different needs, optimizing either for accuracy or efficiency depending on the contract's requirements. ## Types of Equivalence Principles Validators work to reach a consensus on whether the result set by the Leader is acceptable, which might involve direct comparison or qualitative evaluation, depending on the contract’s design. If the validators do not reach a consensus due to differing data interpretations or an error in data processing, the result might be challenged or an appeal process might be initiated. ### Comparative Equivalence Principle In the Comparative Equivalence Principle, both the Leader and the validators perform identical tasks and then directly compare their respective results with the predefined criteria in the Equivalence Principle to ensure consistency and accuracy. This method uses an acceptable margin of error to handle slight variations in results between validators and is suitable for quantifiable outputs. However, since multiple validators perform the same tasks as the Leader, it increases computational demands and associated costs. For example, if an Intelligent Contract is tasked with calculating the average rating of a product based on user reviews, the Equivalence Principle specifies that the average ratings should not differ by more than 0.1 points. Here's how it works: 1. **Leader Calculation**: The Leader validator calculates the average rating from the user reviews and arrives at a rating of 4.5. 2. **Validators' Calculations**: Each validator independently calculates the average rating using the same set of user reviews. Suppose one validator calculates an average rating of 4.6. 3. **Comparison**: The validators compare their calculated average (4.6) with the Leader's average (4.5). According to the Equivalence Principle, the ratings should not differ by more than 0.1 points. 4. **Decision**: Since the difference (0.1) is within the acceptable margin of error, the validators accept the Leader's result as valid. ### Non-Comparative Equivalence Principle In contrast, the Non-Comparative Equivalence Principle does not require validators to replicate the Leader's output, which makes the validation process faster and less costly. Instead, validators assess the accuracy of the Leader’s result against the criteria defined in the Equivalence Principle. This method is particularly useful for qualitative outputs like text summaries. For example, in an Intelligent Contract designed to summarize news articles, the process works as follows: 1. **Leader Summary**: The Leader validator generates a summary of a news article. 2. **Evaluation Criteria**: The Equivalence Principle defines criteria for an acceptable summary, such as accuracy, relevance, and length. 3. **Validators' Assessment**: Instead of generating their own summaries, validators review the Leader’s summary and check if it meets the predefined criteria. - **Accuracy**: Does the summary accurately reflect the main points of the article? - **Relevance**: Is the summary relevant to the content of the article? - **Length**: Is the summary within the acceptable length? 4. **Decision**: If the Leader’s summary meets all the criteria, it is accepted by the validators. ## Key Points for Developers - **Setting Equivalence Criteria:** Developers must define what 'equivalent' means for each non-deterministic operation in their Intelligent Contract. This guideline helps validators judge if different outcomes are close enough to be treated as the same. - **Ensuring Contract Reliability:** By clearly defining equivalence, developers help maintain the reliability and predictability of their contracts, even when those contracts interact with the unpredictable web or complex AI models. # about-genlayer/core-concepts/optimistic-democracy/finality.mdx # Finality Finality refers to the state in which a transaction is considered settled and unchangeable. In GenLayer, once a transaction achieves finality, it cannot be appealed or altered, providing certainty to all participants in the system. This is particularly important for applications that rely on accurate and definitive outcomes, such as financial contracts or decentralized autonomous organizations (DAOs). ## Finality Window The Finality Window is a time frame during which a transaction can be challenged or appealed before it becomes final. This window serves several purposes: 1. **Appeals**: During the Finality Window, any participant can appeal a transaction if they believe the validation was incorrect. This allows for a process of checks and balances, ensuring that non-deterministic transactions are evaluated properly. 2. **Re-computation**: If a transaction is appealed, the system can re-evaluate the transaction with a new set of validators. The Finality Window provides the time necessary for this process to occur. 3. **Security**: The window also acts as a security feature, allowing the network to correct potential errors or malicious activity before finalizing a transaction. import Image from 'next/image' ## Deterministic vs. Non-Deterministic Transactions In GenLayer, Intelligent Contracts are classified as either deterministic or non-deterministic. ### Deterministic Contracts These contracts have a shorter Finality Window because their validation process is straightforward and not subject to appeals. However, it is essential that all interactions with the contract remain deterministic to maintain this efficiency. ### Non-Deterministic Contracts Non-deterministic contracts involve Large Language Model (LLM) calls or web data retrieval, which introduce variability in their outcomes. These contracts require a longer Finality Window to account for potential appeals and re-computation. import { Callout } from 'nextra-theme-docs' If a specific transaction within the contract is deterministic but interacts with a non-deterministic part of the contract, it will be treated as non-deterministic. This ensures that any appeals or re-computations of previous transactions are handled consistently, maintaining the integrity of the contract's overall state. ## Fast Finality For scenarios requiring immediate finality, such as emergency decisions in a DAO, it is possible to pay for all validators to validate the transaction immediately. This approach, though more costly, allows for fast finality, bypassing the typical Finality Window. Fast finality only works if there are no previous non-deterministic transactions still within their Finality Window. Even if your transaction is considered final, if a previous transaction is reverted, your transaction will have to be recomputed as it might depend on the same state. ## Appealability and Gas When submitting a transaction, users can include additional gas to cover potential appeals. If a transaction lacks sufficient gas for appeals, third parties can supply additional gas during the Finality Window. Developers of Intelligent Contracts can also set minimum gas requirements for appealability, ensuring that critical transactions have adequate coverage. # about-genlayer/core-concepts/optimistic-democracy/slashing.mdx # Slashing in GenLayer Slashing is a mechanism used in GenLayer to penalize validators who engage in behavior detrimental to the network. This ensures that validators act honestly and effectively, maintaining the integrity of the platform and the Intelligent Contracts executed within it. By penalizing undesirable behavior, slashing helps align validators' incentives with those of the network and its users. ## Slashing Process 1. **Violation Detection**: The network identifies a violation, such as missing an execution window. 2. **Slash Calculation**: The amount to be slashed is calculated based on the specific violation and platform rules. 3. **Stake Reduction**: The slashed amount is deducted from the validator's stake. 4. **Finality**: The slashing becomes final after the Finality Window closes, ensuring that the validator's balance is finalized and accounts for any potential appeals. ## When Slashing Occurs Validators in GenLayer can be slashed for several reasons: 1. **Missing Transaction Execution Window**: Validators are expected to execute transactions within a specified time frame. If a validator misses this window, they are penalized, ensuring that validators remain active and responsive. 2. **Missing Appeal Execution Window**: During the appeals process, validators must respond within a set time frame. If they fail to do so, they are slashed, which motivates validators to participate in the appeals process. ### Amount Slashed The amount slashed varies based on the severity of the violation and the specific rules set by the GenLayer platform. The slashing amount is designed to be substantial enough to deter malicious or negligent behavior while not being excessively punitive for honest mistakes. # about-genlayer/core-concepts/optimistic-democracy/staking.mdx # Staking in GenLayer Participants, known as validators, commit a specified amount of tokens to the network by locking them up on the rollup layer. This commitment supports the network's consensus mechanism and enables validators to actively participate in processing transactions and managing the network. ## How Staking Works - **Stake Deposit**: To become a validator on GenLayer, participants must deposit GEN tokens on the rollup layer. This deposit acts as a security bond and qualifies them to join the pool of active validators. - **Validator Participation**: Only a certain number of validators, typically between 100 and 1000, with the highest stakes can be part of the active validator set. Once staked, validators take on the responsibility of validating transactions and executing Intelligent Contracts. Their role is crucial for ensuring the network’s reliability and achieving consensus on transaction outcomes. - **Delegated Proof of Stake (DPoS)**: GenLayer enhances accessibility and network security through a Delegated Proof of Stake system. This allows token holders who are not active validators themselves to delegate their tokens to trusted validators. By delegating their tokens, users increase the total stake of the validator and share in the rewards. Typically, the validator takes a configurable fee (around 10%), with the remaining rewards (90%) going to the delegating user. - **Earning Rewards**: Validators, and those who delegate their tokens to them, earn rewards for their contributions to validating transactions, paid in GEN tokens. These rewards are proportional to the amount of tokens staked and the transaction volume processed. - **Risk of Slashing**: Validators, and by extension their delegators, face the risk of having a portion of their staked tokens [slashed](/core-concepts/optimistic-democracy/slashing) if they fail to comply with network rules or if the validator supports fraudulent transactions. ## Unstaking and Withdrawing To stop validating or to retrieve staked tokens, validators must initiate an [unstaking](/core-concepts/optimistic-democracy/unstaking) process, which includes a cooldown period to finalize all pending transactions. This ensures the network remains secure and all obligations are fulfilled before the withdrawal. # about-genlayer/core-concepts/optimistic-democracy/unstaking.mdx # Unstaking in GenLayer Unstaking in GenLayer is the process by which validators disengage their staked tokens from the network, ending their active participation as validators. This procedure ensures that all obligations are fulfilled and pending issues resolved, maintaining the network's integrity and securing the platform’s operations. ## How Unstaking Works The unstaking process includes several key steps: 1. **Initiating Unstaking**: Validators initiate their exit from active duties by submitting an unstaking transaction, signaling their intention to cease participation in validating transactions. 2. **Validator Removal**: Once the unstaking request is made, the validator is promptly removed from the pool of active validators, meaning they will no longer receive new transactions or be called upon for appeal validations. 3. **Finality Period**: During this period, validators must wait for all transactions they have participated in to reach full finality. This is crucial to ensure that validators do not exit while still having potential influence over unresolved transactions. This cooldown period helps prevent the situation where new transactions with new finality windows could prevent them from ever achieving full finality on all transactions they were involved in. 4. **Withdrawing Stake**: After all transactions have achieved finality and no outstanding issues remain, validators and their delegators can safely withdraw their staked tokens and any accrued rewards. ## Purpose of Unstaking The unstaking process is designed to: - **Ensure Accountability**: By enforcing a Finality Window, validators are held accountable for their actions until all transactions they influenced are fully resolved. This prevents premature exit from the network and ensures that all potential disputes are settled. - **Align Incentives**: The requirement for validators to wait through the Finality Window aligns their incentives with the long-term security and reliability of the network, promoting responsible participation. - **Maintain Network Security**: The unstaking process discourages abrupt departures and ensures that validators address any possible security concerns related to their past validations before leaving. ## Implications for Validators and Delegators For validators, this process mandates careful planning regarding their exit strategy from the network, considering the need to wait out the Finality Window. Delegators must also be patient, understanding that their assets will remain locked until their validator has cleared all responsibilities, safeguarding their investments from potential liabilities caused by unresolved validations. # about-genlayer/core-concepts/optimistic-democracy.mdx import { Callout } from 'nextra-theme-docs' # Optimistic Democracy Optimistic Democracy is the consensus method used by GenLayer to validate transactions and operations of Intelligent Contracts. This approach is especially good at handling unpredictable outcomes from transactions involving web data or AI models, which is important for keeping the network reliable and secure. ## Key Components - **Validators:** Participants who stake tokens to earn the right to validate transactions. They play a crucial role in both the initial validation and any appeals process if needed. - **Leader Selection:** A process that randomly picks one validator to propose the outcome for each transaction, ensuring fairness and reducing potential biases. ## How It Works Optimistic Democracy relies on a mix of trust and verification to ensure transaction integrity: ![](/optimistic-democracy-concept.png) 1. **Initial Validation:** When a transaction is submitted, a small group of randomly selected validators checks its validity. One is chosen as the leader. The leader executes the transaction, and the other validators assess the leader's proposal using the Equivalence Principle. 2. **Majority Consensus:** If most validators accept the leader's proposal, the transaction is provisionally accepted. However, this decision is not final yet, allowing for possible appeals during a limited window of time, known as the **Finality Window**. If any validator fails to vote within the specified timeframe, they are replaced, and a new validator is selected to cast a vote. 3. **Initiating an Appeal:** If a participant disagrees with the initial validation (if it's incorrect or fraudulent), they can appeal during the Finality Window. They must submit a request and provide a bond. After the appeal starts, a new group of validators joins the original ones. This group first votes on whether the transaction should be re-evaluated. If they agree, a new leader is chosen to reassess the transaction, and all validators then review this new evaluation. 4. **Appeal Evaluation:** The new leader re-evaluates the transaction, while the other validators assess the leader's proposal using the Equivalence Principle. This step involves more validators, increasing the chances of an accurate decision. 5. **Escalating Appeals:** If the appealing party is still not satisfied, the process can escalate, with each round involving more validators. Each round doubles the number of validators. A new leader is only chosen if the transaction is overturned. 6. **Final Decision:** The appeals process continues until a majority consensus is reached or until all validators have participated. The final decision is recorded, and the transaction's state is updated accordingly. If the appealing party is correct, they receive a reward for their efforts, while incorrect appellants lose their bond. # about-genlayer/core-concepts/rollup-integration.mdx # Rollup Integration GenLayer leverages Ethereum rollups, such as ZKSync or Polygon CDK, to ensure scalability and compatibility with existing Ethereum infrastructure. This integration is crucial for optimizing transaction throughput and reducing fees while maintaining the security guarantees of the Ethereum mainnet. ## Key Aspects of Rollup Integration ### Scalability - **High Transaction Throughput**: Rollups allow GenLayer to process a much higher number of transactions per second compared to Layer 1 solutions. - **Reduced Congestion**: By moving computation off-chain, GenLayer helps alleviate congestion on the Ethereum mainnet. ### Cost Efficiency - **Lower Transaction Fees**: Users benefit from significantly reduced gas fees compared to direct Layer 1 transactions. - **Batched Submissions**: Transactions are batched and submitted to the Ethereum mainnet, distributing costs across multiple operations. ### Security - **Ethereum Security Inheritance**: While execution happens off-chain, the security of assets and final state is guaranteed by Ethereum's robust consensus mechanism. - **Fraud Proofs/Validity Proofs**: Depending on the specific rollup solution (Optimistic or ZK), security is ensured through either fraud proofs or validity proofs. ## How Rollup Integration Works with GenLayer 1. **Transaction Submission**: Users submit transactions to the rollup. 2. **Transaction Execution**: Transactions are executed within the GenVM environment. 3. **Consensus**: The rollup layer implements the Optimistic Democracy mechanism to reach consensus on the state updates. 4. **State Updates**: The rollup layer maintains an up-to-date state of all accounts and contracts. 5. **Batch Submission**: Periodically, batches of transactions and state updates are submitted to the Ethereum mainnet. 6. **Verification**: The Ethereum network verifies the integrity of the submitted data, ensuring its validity. ## Benefits for Developers and Users - **Ethereum Compatibility**: Developers can leverage existing Ethereum tools and infrastructure. - **Improved User Experience**: Lower fees and faster transactions lead to a better overall user experience. ## Considerations - **Withdrawal Periods**: Depending on the rollup solution, there might be waiting periods for withdrawing assets back to the Ethereum mainnet. - **Rollup-Specific Features**: Different rollup solutions may offer unique features or limitations that developers should be aware of. By integrating with Ethereum rollups, GenLayer combines the innovative capabilities of Intelligent Contracts with the scalability and efficiency of Layer 2 solutions, creating a powerful platform for next-generation decentralized applications. # about-genlayer/core-concepts/transactions/transaction-encoding-serialization-and-signing.mdx ## Transaction encoding, serialization, and signing In GenLayer, all three types of transactions needs to be properly encoded, serialized, and signed on the client-side. This process ensures that the transaction data is packaged into a relieable cross-platform efficient format, and securely signed using the sender's private key to verify the sender's identity. Once prepared, the transaction is sent to the network via the `eth_sendRawTransaction` method on the RPC Server. This method performs the inverse process: it decodes and deserializes the transaction data, and then verifies the signature to ensure its authenticity. By handling all transaction types through `eth_sendRawTransaction`, GenLayer ensures that transactions are processed securely and efficiently while maintaining compatibility with Ethereum’s specification. # about-genlayer/core-concepts/transactions/transaction-execution.mdx ## Transaction execution Once a transaction is received and properly verified by the `eth_sendRawTransaction` method on the RPC server, it is stored with a PENDING status and its hash is returned as the RPC method response. This means that the transaction has been validated for authenticity and format, but it has not yet been executed. From this point, the transaction enters the GenLayer consensus mechanism, where it is picked up for execution by the network's validators according to the consensus rules. As the transaction progresses through various stages—such as proposing, committing, and revealing—its status is updated accordingly. Throughout this process, the current status and output of the transaction can be queried by the user. This is done by calling the `eth_getTransactionByHash` method on the RPC server, which retrieves the transaction’s details based on its unique hash. This method allows users to track the transaction’s journey from submission to finalization, providing transparency and ensuring that they can monitor the outcome of their transactions in real-time. ### Transaction Status Transitions - **[*] → Pending**: New transaction submitted by EOA user or internally when processing messages from `proposeReceipt()`. - **[*] → OutOfFee**: Transaction submitted internally lacks sufficient GEN for fees. - **OutOfFee → Pending**: Transaction fee params topped up, satisfying fee restrictions. - **Pending → Proposing**: Transaction moved to proposing stage, leader and voters selected. - **Proposing → Committing**: Leader proposes transaction receipt, validators commit votes and prices. - **Committing → Revealing**: All validators committed, now revealing votes and price estimates. - **Revealing → Accepted**: Majority agrees with proposed receipt. - **Revealing → Rejected**: Consensus on transaction being malformed, failed, or too resource-intensive. - **Revealing → Proposing**: No majority, leader rotated, transaction returns to proposing. - **Revealing → Undetermined**: No consensus after all leader rotations. - **Accepted → Finalized**: Appeal window passes without appeals, transaction finalized. - **Accepted → Appealed**: Transaction appealed within appeal window. - **Appealed → Accepted/Rejected**: Appeals on subsequent transactions canceled, reverting to previous state. - **Appealed → Proposing**: Pre-voting shows disagreement, returns to proposing with new leader/voters. - **Undetermined → Proposing**: Appealed undetermined transaction returns to proposing, affecting subsequent transactions. # about-genlayer/core-concepts/transactions/transaction-statuses.mdx # Transaction Processing In GenLayer, transactions are processed through an account-based queue system that ensures orderliness. Here’s how transactions transition through different statuses: ## 1. Pending When a transaction is first submitted, it enters the pending state. This means it has been received by the network but is waiting to be processed. Transactions are queued per account, ensuring that each account's transactions are processed in the order they were submitted. ## 2. Proposing In this stage, the transaction is moved from the pending queue to the proposing stage. A leader and a set of voters are selected from the validator set via a weighted random selection based on total stake. The leader proposes a receipt for the transaction, which is then committed to by the validators. ## 3. Committing The transaction enters the committing stage, where validators commit their votes and cost estimates for processing the transaction. This stage is crucial for reaching consensus on the transaction's execution. ## 4. Revealing After the committing stage, validators reveal their votes and cost estimates, allowing the network to finalize the transaction's execution cost and validate the consensus. ## 5. Accepted Once the majority of validators agree on the transaction's validity and cost, the transaction is marked as accepted. This status indicates that the transaction has passed through the initial validation process successfully. ## 6. Finalized After all validations are completed and any potential appeals have been resolved, the transaction is finalized. In this state, the transaction is considered irreversible and is permanently recorded in the blockchain. ## 7. Undetermined If the transaction fails to reach consensus after all voting rounds, it enters the undetermined state. This status indicates that the transaction's outcome is unresolved, and it may require further validation or be subject to an appeal process. ## 8. Canceled A transaction can be canceled by the user or by the system if it fails to meet certain criteria (e.g., insufficient funds). Once canceled, the transaction is removed from the processing queue and will not be executed. # about-genlayer/core-concepts/transactions/types-of-transactions.mdx # Types of Transactions There are three different types of transactions that users can send in GenLayer. All three types are sent through the same RPC method, but they differ in the data they contain and the actions they perform. ## 1. Deploy a Contract Deploying a contract involves creating a new Intelligent Contract on the GenLayer network. This transaction initializes the contract"s state and assigns it a unique address on the blockchain. The deployment process ensures that the contract code is properly validated and stored, making it ready to be called. ### Example ```json { "consensus_data": { "leader_receipt": { "args": [ { "total_supply": 100 } ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", ... }, "validators": [ ... ], ... }, "data": { "constructor_args": "{\"total_supply\":100}", "contract_address": "0x5929bB548a2Fd7E9Ea2577DaC9c67A08BbC2F356", "contract_code": "import json\nfrom backend.node.genvm.icontract import IContract\nfrom backend.node.genvm.equivalence_principle import EquivalencePrinciple\n\n\nclass LlmErc20(IContract):\n def __init__(self, total_supply: int) -> None:\n self.balances = {}\n self.balances[contract_runner.from_address] = total_supply\n...", }, ... } ``` ## 2. Send Value Sending value refers to transferring the native GEN token from one account to another. This is one of the most common types of transactions. Each transfer updates the balance of the involved accounts, and the transaction is recorded on the blockchain to ensure transparency and security. ### Example ```json { "consensus_data": null, "created_at": "2024-10-02T21:21:04.192995+00:00", "data": {}, "from_address": "0x0Bd6441CB92a64fA667254BCa1e102468fffB3f3", "gaslimit": 0, "hash": "0x6357ec1e86f003b20964ef3b2e9e072c7c9521f92989b08e04459b871b69de89", "leader_only": false, "nonce": 2, "r": null, "s": null, "status": "FINALIZED", "to_address": "0xf739FDe22E0C0CB6DFD8f3F8D170bFC07329489E", "type": 0, "v": null, "value": 200 } ``` ## 3. Call Contract Function Calling a contract function is the process of invoking a specific method within an existing Intelligent Contract. This could involve anything from querying data stored within the contract to executing more complex operations like transferring tokens or interacting with other contracts. Each function call is a transaction that modifies the contract’s state based on the inputs provided. ### Example ```json { "consensus_data": { "leader_receipt": { "args": [ [ 2, "0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2" ] ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", "eq_outputs": { "leader": { "0": "{\"transaction_success\": true, \"transaction_error\": \"\", \"updated_balances\": {\"0xD271c74A78083F357a9f8d31d5adC59B395cf16b\": 98, \"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\": 2}}" } }, ... }, "validators": [ ... ], ... }, "data": { "function_args": "[2,\"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\"]", "function_name": "transfer" }, ... } ``` * For a list of all the fields in a transaction, see [here](/core-concepts/transactions) # about-genlayer/core-concepts/transactions.mdx # Transactions Transactions are the fundamental operations that drive the GenLayer protocol. Whether it's deploying a new contract, sending value between accounts, or invoking a function within an existing contract, transactions are the means by which state changes occur on the network. Here is the general structure of a transaction: ```json { "consensus_data": { "leader_receipt": { "args": [ [ 2, "0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2" ] ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", "eq_outputs": { "leader": { "0": "{\"transaction_success\": true, \"transaction_error\": \"\", \"updated_balances\": {\"0xD271c74A78083F357a9f8d31d5adC59B395cf16b\": 98, \"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\": 2}}" } }, "error": null, "execution_result": "SUCCESS", "gas_used": 0, "method": "transfer", "mode": "leader", "node_config": { "address": "0x185D2108D9dE15ccf6beEb31774CA96a4f19E62B", "config": {}, "model": "gpt-4o", "plugin": "openai", "plugin_config": { "api_key_env_var": "OPENAIKEY", "api_url": null }, "provider": "openai", "stake": 1 }, "vote": "agree" }, "validators": [ { "args": [ [ 2, "0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2" ] ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", "eq_outputs": { "leader": { "0": "{\"transaction_success\": true, \"transaction_error\": \"\", \"updated_balances\": {\"0xD271c74A78083F357a9f8d31d5adC59B395cf16b\": 98, \"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\": 2}}" } }, "error": null, "execution_result": "SUCCESS", "gas_used": 0, "method": "transfer", "mode": "validator", "node_config": { "address": "0x31bc9380eCbF487EF5919eBa7457F457B5196FCD", "config": {}, "model": "gpt-4o", "plugin": "openai", "plugin_config": { "api_key_env_var": "OPENAIKEY", "api_url": null }, "provider": "openai", "stake": 1 }, "pending_transactions": [], "vote": "agree" }, ... ], "votes": { "0x185D2108D9dE15ccf6beEb31774CA96a4f19E62B": "agree", "0x2F04Fb1e5daf7DCbf170E4CB0e427d9b11aB96cA": "agree", "0x31bc9380eCbF487EF5919eBa7457F457B5196FCD": "agree" } }, "created_at": "2024-10-02T20:32:50.469443+00:00", "data": { "function_args": "[2,\"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\"]", "function_name": "transfer" }, "from_address": "0xD271c74A78083F357a9f8d31d5adC59B395cf16b", "gaslimit": 66, "hash": "0xb7486f70a3fec00af5f929fc1cf1078af9ff3a063afe8b6f370a44a96635505d", "leader_only": false, "nonce": 66, "r": null, "s": null, "status": "FINALIZED", "to_address": "0x5929bB548a2Fd7E9Ea2577DaC9c67A08BbC2F356", "type": 2, "v": null, "value": 0 } ``` ## Explanation of fields: - consensus_data: Object containing information about the consensus process - leader_receipt: Object containing details about the leader's execution of the transaction - args: Arguments passed to the contract function - class_name: Name of the contract class - contract_state: Encoded state of the contract - eq_outputs: Outputs from every equivalence principle in the execution of the contract method - error: Any error that occurred during execution (null if no error) - execution_result: Result of the execution (e.g., "SUCCESS" or "ERROR") - gas_used: Amount of gas used in the transaction - method: Name of the method called on the contract - mode: Execution mode (e.g., "leader" or "validator") - node_config: Configuration of the node executing the transaction - address: Address of the node - config: Configuration of the node - model: Model of the node - plugin: Plugin used for the LLM provider connection - plugin_config: Configuration of the plugin - api_key_env_var: Environment variable containing the API key for the given provider - api_url: API URL for the given provider - provider: Provider of the node - stake: Stake of the validator - vote: The leader's vote on the transaction (e.g., "agree") - validators: Array of objects containing similar information for each validator - votes: Object mapping validator addresses to their votes - created_at: Timestamp of when the transaction was created - data: Object containing details about the function call in the transaction - from_address: Address of the account initiating the transaction - gaslimit: Maximum amount of gas the transaction is allowed to consume - hash: Unique identifier (hash) of the transaction - leader_only: Boolean indicating whether the transaction is to be executed by the leader node only - nonce: Number of transactions sent from the from_address (used to prevent double-spending) - r: Part of the transaction signature (null if not yet signed) - s: Part of the transaction signature (null if not yet signed) - status: Current status of the transaction (e.g., "FINALIZED") - to_address: Address of the contract or account receiving the transaction - type: Internal type of the transaction (2 indicates a contract write call) - v: Part of the transaction signature (null if not yet signed) - value: Amount of native currency (GEN) being transferred in the transaction # about-genlayer/core-concepts/validators-and-validator-roles.mdx # Validators and Validator Roles ## Overview Validators are essential participants in the GenLayer network. They are responsible for validating transactions and maintaining the integrity and security of the blockchain. Validators play a crucial role in the Optimistic Democracy consensus mechanism, ensuring that both deterministic and non-deterministic transactions are processed correctly. ## Key Responsibilities - **Transaction Validation**: Validators verify the correctness of transactions proposed by the leader, using mechanisms like the Equivalence Principle for non-deterministic operations. - **Leader Selection**: Validators participate in the process of randomly selecting a leader for each transaction, ensuring fairness and decentralization. - **Consensus Participation**: Validators cast votes on proposed transaction outcomes, contributing to the consensus process. - **Staking and Incentives**: Validators stake tokens to earn the right to validate transactions and receive rewards based on their participation and correctness. ## Validator Selection and Roles - **Leader Validator**: For each transaction, a leader is randomly selected among the validators. The leader is responsible for executing the transaction and proposing the result to other validators. - **Consensus Validators**: Other validators assess the leader's proposed result and vote to accept or reject it based on predefined criteria. ## Becoming a Validator - **Staking Requirement**: Participants must stake a certain amount of tokens to become validators. - **Validator Configuration**: Validators must configure their nodes with the appropriate LLM providers and models, depending on the network's requirements. - **Reputation and Slashing**: Validators must act honestly to avoid penalties such as slashing of their staked tokens. # about-genlayer/core-concepts/web-data-access.mdx # Web Data Access in Intelligent Contracts ## Overview GenLayer enables Intelligent Contracts to directly access and interact with web data, removing the need for oracles and allowing for real-time data integration into blockchain applications. ## Key Features - **Direct Web Access**: Contracts can retrieve data from web sources. - **Dynamic Applications**: Access to web data allows for applications that respond to external events and real-world data. - **Equivalence Validation**: Retrieved data is validated across validators to ensure consistency. ## Implementation 1. **Data Retrieval Functions**: GenLayer provides mechanisms for fetching web data within contracts. 2. **Data Parsing and Validation**: Contracts must parse web data and validate it according to defined equivalence criteria. 3. **Security Measures**: Contracts should handle potential security risks such as untrusted data sources and ensure data integrity. ## Considerations - **Network Dependencies**: Reliance on external web sources introduces dependencies that may affect contract execution. - **Performance Impact**: Web data retrieval may introduce latency and affect transaction processing times. # about-genlayer/core-concepts.mdx import { Card, Cards } from 'nextra-theme-docs' ## GenLayer Core Concepts Explore the fundamental ideas that drive the GenLayer platform. Each section provides a detailed look at the key components and mechanisms that make GenLayer's Intelligent Contracts reliable, secure, and efficient. # about-genlayer/optimistic-democracy-consensus.mdx # Optimistic Democracy Consensus Mechanism GenLayer stands out with its unique consensus mechanism called **Optimistic Democracy**. This mechanism uses the Equivalence Principle and a structured appeal process to reach consensus on subjective and non-deterministic transactions. import Image from 'next/image' ![](/genlayer-works.png) ## How the Optimistic Democracy Mechanism Work When a transactions is submitted on GenLayer, a randomly selected group of five validators is assigned to verify each transaction. However, you can adjust the number of validators for your specific projects, allowing for higher security guarantees. When a transaction is submitted to the network, one of the selected validators is chosen as the leader. The leader executes the transaction and proposes an output, which the other validators then evaluate using the Equivalence Principles set by the developer. The number of validators is always odd, ensuring a consensus is reached. ![Consensus](/consensus-model.jpg) If a majority of the validators agree with the leader’s outputs, the transaction is considered valid. This ensures that while the outputs may not be identical, they are equivalent within the project’s requirements. Once a transaction has gone through the Optimistic Execution process and without any necessary appeals, it reaches a state of Finality. Unlike Ethereum, where finality is typically reached within 6–12 minutes, GenLayer allows for a more extended validation period to accommodate appeals, enhancing reliability. For more detailed information, refer to the [concept section](/core-concepts). # about-genlayer/what-are-intelligent-contracts.mdx # What are Intelligent Contracts? Intelligent Contracts are AI-powered smart contracts that uses large language models (LLMs) to access real-time web data and understand natural language. Unlike traditional smart contracts, which execute predefined blockchain actions, intelligent contracts dynamically interact with external data and adapt to changing conditions, modifying their operations as new information becomes available. ## Difference Between Smart Contracts and Intelligent Contracts | Feature | Smart Contracts | Intelligent Contracts | |--------------------------------|---------------------------------------------------------|--------------------------------------------------------| | **Definition** | Self-executing contracts with terms written into code | Advanced smart contracts powered by AI, capable of interacting with web data and process natural language | | **Capabilities** | Executes predefined blockchain actions | Executes blockchain actions and can access web data, process natural language, and use AI | | **Language Understanding** | Executes code-specific commands only | Capable of interpreting and acting on natural language | | **Web Data Access** | Relies on external services (oracles) for web data | Direct access to web data without intermediaries | | **Data Handling** | Limited to data within the blockchain | Directly fetches and utilizes web data | | **Programming Language** | Typically uses niche languages like Solidity | Uses more familiar languages like Python | | **Ease of Development** | Requires blockchain-specific knowledge | More accessible for a wider range of developers due to familiar languages and tools | | **Flexibility** | Performs static operations based on predefined conditions| Adapts and responds dynamically to real-time data | | **Consensus Mechanism** | Uses standard blockchain consensus methods | Uses "Optimistic Democracy" for more reliable outcomes | | **Use Cases** | Generally limited to predefined scenarios like payments and apps | Supports dynamic applications like smart oracles, interactive games, and AI-driven decentralized applications | This table highlights how Intelligent Contracts offer significant advantages over traditional smart contracts, enabling more complex, responsive, and secure blockchain applications. # about-genlayer.mdx # What is GenLayer? GenLayer is a blockchain platform designed to execute AI-powered smart contracts. It uses multiple validators, each connected to a different Large Language Models (LLM). These validators collaborate and verify each other's work through a unique consensus algorithm called **Optimistic Democracy**. This method enables them to reach agreements on non-deterministic instructions, such as processing text prompts and reading data from the web, making GenLayer highly dynamic and adaptable. import Image from 'next/image' ![](/evolution.jpeg) ## What Makes GenLayer Different? - **AI-Powered**: The integration of AI allows for smarter contracts that can process natural language and make data-driven decisions in real time. - **Web Data Access**: GenLayer's Intelligent Contracts can natively access real-time data from the web, making them more responsive and reliable compared to traditional smart contracts that rely on oracles. - **Secure and Reliable**: GenLayer uses a unique model called **"Optimistic Democracy"** consensus mechanism, to handle non-deterministic operations, where the same transaction can produce different results. ensuring efficient and secure transaction validation. - **Interoperability**: GenLayer is designed for seamless interoperability with other blockchain platforms and traditional web services. - **Python-based SDK**: GenLayer uses Python, which simplifies the development of Intelligent Contracts. ## How GenLayer Works ![](/genlayer-works.png) 1. **User Submits a Transaction**: A user submits a transaction to the GenLayer network. 2. **Result Proposed**: A validator is randomly selected to act as the leader. The leader processes the transaction and proposes a result. 3. **Result Validated**: A group of validators assesses the leader's proposed result. They use the Equivalence Principle to ensure the result is accurate and fair. 4. **Result Accepted**: If the majority of validators agree with the leader’s proposal, the result is provisionally accepted. 5. **Can Appeal**: If any participant disagrees with the initial validation, they can appeal the decision within a limited time window, known as the Finality Window. They submit a request and provide a bond for the appeal process. 6. **Additional Validation (if appealed)**: If an appeal is initiated, a new group of validators re-evaluates the transaction. This group first votes on whether the transaction should be re-evaluated. If they agree, a new leader is chosen to reassess the transaction, and all validators review this new evaluation. 7. **Final Decision**: The process continues until a final consensus is reached. If the appealing party's appeal is valid, they are rewarded, while incorrect appellants lose their bond. Once all appeals are resolved, the result becomes final. ## Typical Use Cases - **Prediction Markets**: Create decentralized platforms where users can trade on the outcomes of events. This is useful in finance for predicting stock market movements, in sports for betting on match results, and in entertainment for forecasting award winners. - **Performance-Based Contracting**: Automate escrow and payment mechanisms based on performance metrics. Intelligent Contracts can access work outputs on the web and automatically release payments to freelancers or contractors. - **Network States**: Create truly decentralized governance mechanisms for Network States. Explore the future of decentralized governance with GenLayer. - **Dispute Resolution**: GenLayer is a decentralized AI-powered court that can resolve disputes at a fraction of the cost and time of traditional legal systems. - **AI-Driven DAOs**: Develop decentralized autonomous organizations that are managed by AI algorithms. These DAOs can make real-time decisions based on data analysis, enhancing governance, investment strategies, and community projects. For more use cases, visit [Build With GenLayer](https://docs.genlayer.com/build-with-genlayer/ideas). ## Why Are We Building This? We are building GenLayer to overcome the limitations of traditional smart contracts. Smart contracts can't directly interact with the outside world without oracles and are limited to code-based instructions. By integrating AI, GenLayer's Intelligent Contracts can process natural language and interact with web data, enabling a wide range of new applications. Our goal is to create a more dynamic protocol where intelligent entities can sign contracts and transfer value in ways that align with real-world interactions. GenLayer's **"Optimistic Democracy"** consensus algorithm ensures secure and efficient handling of non-deterministic outputs, making the platform adaptable and reliable. In essence, GenLayer aims to push the boundaries of blockchain technology, allowing for more sophisticated, responsive, and interactive applications. ## Who is GenLayer for? GenLayer is for: - **Exisitng dApps**: Replace human-based oracles and decision-making with AI-powered Intelligent Contracts, vastly reducing the cost and time of operations. - **Builders**: Build never-before-possible decentralized applications with the power of AI and web access. - **Enterprises**: Automate complex processes, contracts and decision-making with AI-powered Intelligent Contracts. - **Researchers**: Explore the future of decentralized governance with GenLayer. - **Everyone**: Participate in the future of AI-powered blockchain technology. # api-references/genlayer-cli.mdx # GenLayer CLI Reference Each command includes syntax, usage information, and examples to help you effectively use the CLI for interacting with the GenLayer environment. ## Command line syntax General syntax for using the GenLayer CLI: ```bash genlayer command [command options] [arguments...] ``` ## Commands and usage ### Initialize Prepares and verifies your environment to run the GenLayer Studio. ```bash USAGE: genlayer init [options] OPTIONS: --numValidators Number of validators (default: "5") --branch Branch to use (default: "main") EXAMPLES: genlayer init genlayer init --numValidators 10 --branch develop ``` ### Start GenLayer environment Launches the GenLayer environment and the Studio, initializing a fresh set of database and accounts. ```bash USAGE: genlayer up [options] OPTIONS: --reset-validators Remove all current validators and create new random ones (default: false) --numValidators Number of validators (default: "5") --branch Branch to use (default: "main") EXAMPLES: genlayer up genlayer up --reset-validators --numValidators 8 --branch feature-branch ``` # api-references/genlayer-js.mdx # GenLayerJS SDK Reference This document describes the key components and methods available in the GenLayerJS SDK for interacting with the GenLayer network. ## Client Creation ### createClient Creates a new GenLayer client instance. ```typescript import { createClient } from 'genlayer-js'; const client = createClient({ chain: simulator, account: account, // Optional: Use this account for subsequent calls }); ``` **Parameters:** - `chain`: The chain configuration (e.g., simulator) - `account`: (Optional) Sets an account to be used in subsequent calls **Returns:** A GenLayer client instance ## Transaction Handling ### getTransaction Retrieves transaction details by hash. ```typescript const transaction = await client.getTransaction({ hash: transactionHash }); ``` **Parameters:** - `hash`: The transaction hash **Returns:** Transaction details object

### waitForTransactionReceipt Waits for a transaction receipt. ```typescript const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: 'FINALIZED', // or 'ACCEPTED' }); ``` **Parameters:** - `hash`: The transaction hash - `status`: The desired transaction status ('FINALIZED' or 'ACCEPTED') **Returns:** Transaction receipt object ## Contract Interaction ### readContract Reads data from a deployed contract. ```typescript const result = await client.readContract({ address: contractAddress, functionName: 'get_complete_storage', args: [], }); ``` **Parameters:** - `address`: The contract address - `functionName`: The name of the function to call - `args`: An array of arguments for the function call **Returns:** The result of the contract function call

### writeContract Writes data to a deployed contract. ```typescript const transactionHash = await client.writeContract({ address: contractAddress, functionName: 'storeData', args: ['new_data'], value: 0, // Optional: amount of native token to send with the transaction }); ``` **Parameters:** - `address`: The contract address - `functionName`: The name of the function to call - `args`: An array of arguments for the function call - `value`: (Optional) Amount of native token to send with the transaction **Returns:** The transaction hash ## Account Management ### generatePrivateKey Generates a new private key. ```typescript import { generatePrivateKey } from 'genlayer-js'; const privateKey = generatePrivateKey(); ``` **Parameters:** None **Returns:** A new private key as string

### createAccount Creates a new account, optionally using a provided private key. ```typescript import { createAccount } from 'genlayer-js'; const account = createAccount(); // Or with a specific private key: const accountWithKey = createAccount('0x1234...'); // Replace with actual private key ``` **Parameters:** - `accountPrivateKey`: (Optional) A string representing the private key **Returns:** A new account object ## Chain Information ### simulator Provides configuration for the GenLayer Studio chain (the Studio used to be called "Simulator"). ```typescript import { simulator } from 'genlayer-js/chains'; ``` **Usage:** Used when creating a client to specify the chain # api-references/json-rpc.mdx # JSON-RPC API Reference This document describes the JSON-RPC methods available in the Studio. ## Studio Methods ### sim_clearDbTables Clears specified database tables. **Parameters:** - `tables`: An array of table names to clear. **Returns:** None

### sim_fundAccount Funds an account with a specified amount. **Parameters:** - `account_address`: The address of the account to fund. - `amount`: The amount to fund the account with. **Returns:** Transaction hash (string)

### sim_getProvidersAndModels Retrieves all providers and models. **Parameters:** None **Returns:** An array of provider and model objects.

### sim_resetDefaultsLlmProviders Resets LLM providers to default settings. **Parameters:** None **Returns:** None

### sim_addProvider Adds a new LLM provider. **Parameters:** - `provider`: Provider name. - `model`: Model name. - `config`: Provider configuration. - `plugin`: Plugin name. - `plugin_config`: Plugin configuration. **Returns:** Provider ID (integer)

### sim_updateProvider Updates an existing LLM provider. **Parameters:** - `id`: Provider ID to update. - `provider`: Updated provider name. - `model`: Updated model name. - `config`: Updated provider configuration. - `plugin`: Updated plugin name. - `plugin_config`: Updated plugin configuration. **Returns:** None

### sim_deleteProvider Deletes an LLM provider. **Parameters:** - `id`: Provider ID to delete. **Returns:** None

### sim_createValidator Creates a new validator. **Parameters:** - `stake`: Validator's stake amount. - `provider`: LLM provider name. - `model`: LLM model name. - `config`: (Optional) Provider configuration. - `plugin`: (Optional) Plugin name. - `plugin_config`: (Optional) Plugin configuration. **Returns:** Validator details (object)

### sim_createRandomValidator Creates a random validator. **Parameters:** - `stake`: Validator's stake amount. **Returns:** Validator details (object)

### sim_createRandomValidators Creates multiple random validators. **Parameters:** - `count`: Number of validators to create. - `min_stake`: Minimum stake amount. - `max_stake`: Maximum stake amount. - `limit_providers`: (Optional) Array of allowed provider names. - `limit_models`: (Optional) Array of allowed model names. **Returns:** Array of validator details (objects)

### sim_updateValidator Updates an existing validator. **Parameters:** - `validator_address`: Address of the validator to update. - `stake`: Updated stake amount. - `provider`: Updated LLM provider name. - `model`: Updated LLM model name. - `config`: (Optional) Updated provider configuration. - `plugin`: (Optional) Updated plugin name. - `plugin_config`: (Optional) Updated plugin configuration. **Returns:** Updated validator details (object)

### sim_deleteValidator Deletes a validator. **Parameters:** - `validator_address`: Address of the validator to delete. **Returns:** Deleted validator address (string)

### sim_deleteAllValidators Deletes all validators. **Parameters:** None **Returns:** Array of remaining validators (should be empty)

### sim_getAllValidators Retrieves all validators. **Parameters:** None **Returns:** Array of validator details (objects)

### sim_getValidator Retrieves a specific validator. **Parameters:** - `validator_address`: Address of the validator to retrieve. **Returns:** Validator details (object)

### sim_countValidators Counts the number of validators. **Parameters:** None **Returns:** Number of validators (integer) ## GenLayer Specific Methods ### gen_getContractSchema Retrieves the schema for a deployed contract. **Parameters:** - `contract_address`: Address of the deployed contract. **Returns:** Contract schema (object)

### gen_getContractSchemaForCode Retrieves the schema for given contract code. **Parameters:** - `contract_code`: The contract code to analyze. **Returns:** Contract schema (object) ## Ethereum-compatible Methods ### eth_getBalance Retrieves the balance of an account. **Parameters:** - `account_address`: The address of the account. - `block_tag`: (Optional) The block number or tag (default: "latest"). **Returns:** Account balance (integer)

### eth_getTransactionByHash Retrieves transaction details by hash. **Parameters:** - `transaction_hash`: The hash of the transaction. **Returns:** Transaction details (object)

### eth_call Executes a new message call without creating a transaction. **Parameters:** - `params`: An object containing: - `to`: The address of the contract to call. - `from`: (Optional) The address the call is made from. - `data`: The call data. - `block_tag`: (Optional) The block number or tag (default: "latest"). **Returns:** The return value of the executed contract method

### eth_sendRawTransaction Sends a signed transaction. **Parameters:** - `signed_transaction`: The signed transaction data. **Returns:** Transaction hash (string) # api-references.mdx import { Card, Cards } from 'nextra-theme-docs' # developers/decentralized-applications/architecture-overview.mdx # Architecture Overview of Decentralized Applications Using GenLayer A decentralized application (DApp) on GenLayer leverages its unique blockchain architecture to integrate AI-powered smart contracts, called "Intelligent Contracts." These DApps consist of various components that work together to ensure seamless interaction with the GenLayer protocol. ## Key Components ### Frontend Application The user interface of the DApp is typically built with web technologies like HTML, CSS, and JavaScript. It communicates with the backend using the GenLayerJS SDK, enabling interaction with the GenLayer protocol and handling user inputs to trigger blockchain transactions. ### GenLayerJS SDK A TypeScript/JavaScript library that abstracts the complexities of blockchain interactions. The SDK provides APIs to read from and write to Intelligent Contracts, manages accounts and queries transactions, and acts as the bridge between the frontend and GenLayer's protocol. ### Consensus Layer The consensus layer implements GenLayer's Optimistic Democracy mechanism to ensure reliable and secure execution of transactions using a validator-driven commit-reveal scheme. It also handles appeals and transaction finality to maintain integrity and fairness. It is built on ZK-stack rollups to provide scalability and cost-efficiency, secure state updates, and anchoring to Ethereum's security model. ### Execution Environment The execution environment (the GenVM) is the engine that executes Intelligent Contracts. It supports both deterministic and non-deterministic operations, enabling AI integration and web data access. ### Ghost Contracts Ghost contracts are proxy smart contracts on the consensus layer that facilitate interactions between accounts and Intelligent Contracts. They also manage external messages and asset bridging. ## Architecture Diagram ```mermaid flowchart TD subgraph s1["Frontend Application"] n1["GenLayerJS"] end subgraph s2["Consensus Layer."] n2["Consensus Smart Contracts"] n3["Ghost Contracts"] end subgraph s3["GenLayer Node"] n4["Execution Environment - GenVM"] end s1 <--> s3 s3 <--> s2 ``` # developers/decentralized-applications/dapp-development-workflow.mdx # DApp Development Workflow with GenLayer The GenLayer platform allows developers to create decentralized applications (DApps) throughout the lifecycle of creating, testing, and deploying. This guide details how developers can transition from using the **GenLayer Studio** for their first Intelligent Contract to an advanced local development workflow, finishing with building a frontend application with **GenLayerJS**. --- ## 1. Starting with GenLayer Studio **GenLayer Studio** is an integrated environment designed to streamline the initial stages of Intelligent Contract development, making it accessible for developers of all experience levels. It provides an interactive environment that serves as a comprehensive sandbox for developing, deploying, and testing Intelligent Contracts in real time. This environment enables developers to experiment with their contracts and see immediate results without the complexities of a production setup. The platform runs a simulated network with customizable validators that accurately mirror the GenLayer consensus mechanism. This feature allows developers to test their contracts under conditions that closely resemble the actual blockchain environment, ensuring reliable deployment outcomes. ### Getting Started: 1. **Set Up the Studio**: Developers initialize the Studio using `genlayer cli` command `genlayer init` which configures the environment and spawns a local validator network. GenLayer Studio is also available as a hosted instace at [studio.genlayer.com](https://studio.genlayer.com/). 2. **Write Your First Contract**: Intelligent Contracts in GenLayer are written in Python, utilizing its extensive libraries and GenVM capabilities like LLM calls and web integration. Refer to [Your First Contract](/developers/intelligent-contracts/your-first-contract) guide for more information. 3. **Deploy and Test**: Deploy your Intelligent Contracts through the Studio interface and test them in the simulated network. --- ## 2. Moving to Advanced Workflow As projects transforms to real-world applications, developers should migrate to a local development setup. This approach mirrors frameworks like Hardhat or Foundry and is well-suited for iterative development and comprehensive testing. ### Benefits of Local Development: - **Complete Control**: Developers can configure the environment, validators, and network parameters as needed. - **Enhanced Debugging**: The local setup allows for advanced debugging of both contracts and transactions. - **Flexible Testing**: Tests can simulate real-world scenarios, including edge cases and complex interactions. ### Workflow Steps: 1. **Set Up Your Local Environment**: Developers can start with the GenLayer boilerplate project, which includes pre-configured templates for local testing. 2. **Write Tests**: Tests are written in Python, focusing on validating contract functionality and ensuring consensus integrity. The boilerplate includes sample tests to accelerate development. 3. **Simulate Transactions**: Run detailed simulations to observe how contracts behave under various network conditions, ensuring robust performance. --- ## 3. Building the Frontend with GenLayerJS The frontend is the user-facing component of a DApp. With **GenLayerJS**, developers can integrate their applications with the GenLayer network, focusing on providing a seamless user experience. ### Why Use GenLayerJS? - **Simplified Interactions**: Abstracts the complexity of blockchain interactions with high-level APIs. - **Comprehensive Features**: Supports transaction handling, contract interaction, event subscriptions, and account management. - **TypeScript Integration**: Provides type safety and code reliability for frontend development. ### Frontend Development Workflow: 1. **Integrate GenLayerJS**: Install the SDK and set up a client to connect to the GenLayer network. Configuration options allow connection to various environments, such as testnets or the GenLayer Studio. Refer to [GenLayerJS](/developers/decentralized-applications/genlayer-js) guide for more information. 2. **Read and Write to Contracts**: Use the SDK's high-level APIs to interact with deployed contracts. For instance, retrieve user balances or update contract state seamlessly. Refer to [Reading Data](/developers/decentralized-applications/reading-data) and [Writing Data](/developers/decentralized-applications/writing-data) guides for more information. 3. **Monitor Transactions**: Developers can subscribe to events or query transaction statuses, ensuring users are kept informed of transaction progress and outcomes. 4. **Build the User Interface**: Combine GenLayerJS with popular frontend frameworks (like React or Angular) to create intuitive interfaces. --- ## Advanced Tips for Developers 1. **Leverage GenVM Features**: GenVM allows Intelligent Contracts to interact with LLM models and access real-time web data. Developers should design contracts to maximize these capabilities for dynamic and intelligent DApps. 2. **Optimize Testing**: Incorporate edge case scenarios in tests to ensure that contracts behave reliably under all conditions. 3. **Focus on Security**: Implement robust security measures, including input validation and error handling, to protect contracts from malicious inputs and ensure consensus consistency. # developers/decentralized-applications/genlayer-js.mdx # GenLayerJS SDK GenLayerJS SDK is a TypeScript library designed for developers building decentralized applications (DApps) on the GenLayer protocol. This SDK provides a comprehensive set of tools to interact with the GenLayer network, including client creation, transaction handling, event subscriptions, and more, all while leveraging the power of Viem as the underlying blockchain client. ## Features - **Client Creation**: Easily create and configure a client to connect to GenLayer’s network. - **Transaction Handling**: Send and manage transactions on the GenLayer network. - **Contract Interaction**: Read from and write to smart contracts deployed on GenLayer. - **Event Subscriptions**: Subscribe to events and listen for blockchain updates. - **TypeScript Support**: Benefit from static typing and improved code reliability. ## How it's Built The GenLayerJS SDK is built using **TypeScript** and leverages the **Viem** library as the underlying blockchain client. It is designed to provide a high-level, easy-to-use API for interacting with the GenLayer network, abstracting away the complexities of direct blockchain interactions. ### Technologies Used - **TypeScript**: A statically typed superset of JavaScript that compiles to plain JavaScript, enhancing code reliability and maintainability. - **Viem**: A modular and extensible blockchain client for JavaScript and TypeScript. - **ESBuild**: A fast JavaScript bundler and minifier used for building the SDK efficiently. - **Vitest**: A Vite-native unit test framework used for testing. ### Project Structure The source code for the GenLayerJS SDK is organized as follows: - `src/`: Contains the main TypeScript source files. - `tests/`: Includes all the test files written using Vitest. - `dist/`: The compiled JavaScript files ready for use. ## Requirements Before using the GenLayerJS SDK, ensure your system meets the following requirements: - **Node.js**: Version 16.x or higher is required. - **npm**: Comes bundled with Node.js, used for managing packages. - **Operating System**: Compatible with macOS, Linux, and Windows. ### Installation To install the GenLayerJS SDK in , use the following command: ```bash npm install genlayer-js ``` ## Usage Here’s how to initialize the client and connect to the GenLayer Studio: ### Reading a Transaction ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient } from 'genlayer-js'; const client = createClient({ chain: simulator, }); const transactionHash = "0x..."; const transaction = await client.getTransaction({ hash: transactionHash }); ``` ### Reading a Contract ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient, createAccount } from 'genlayer-js'; const account = createAccount(); const client = createClient({ chain: simulator, account: account, // Use this account for subsequent calls }); const result = await client.readContract({ address: contractAddress, functionName: 'get_complete_storage', args: [], }); ``` ### Writing a Transaction ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient, createAccount } from 'genlayer-js'; const account = createAccount(); const client = createClient({ chain: simulator, account: account, }); const transactionHash = await client.writeContract({ address: contractAddress, functionName: 'update_storage', args: ['new_data'], value: 0, // Optional: amount of native token to send with the transaction }); const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: 'FINALIZED', // or 'ACCEPTED' }); ``` ## General Format of Commands The GenLayerJS SDK provides functions that follow a consistent syntax pattern: ```typescript client.functionName(parameters); ``` - `client`: The instance of the GenLayer client. - `functionName`: The primary action you want to perform (e.g., `getTransaction`, `readContract`). - `parameters`: An object containing the required parameters for the function. ## Further Development Additional features are planned to enhance interaction with the GenLayer network, including wallet integration and gas estimation. Stay tuned for updates. ## Repository You can find the GenLayerJS SDK repository on GitHub: [GenLayerJS SDK Repository](https://github.com/yeagerai/genlayer-js) ## Full Reference The full reference for the GenLayerJS SDK is available in the [GenLayerJS SDK Reference](/references/genlayer-js). # developers/decentralized-applications/project-boilerplate.mdx import { Callout } from 'nextra-theme-docs' # GenLayer Project Boilerplate The GenLayer Project Boilerplate is a template for building decentralized applications (DApps) on GenLayer. This boilerplate includes a complete example implementation of a football prediction market, demonstrating best practices and common patterns for GenLayer development. This boilerplate is a work in progress and is not yet ready for production use. You can find the latest version at: [GenLayer Project Boilerplate](https://github.com/yeagerai/genlayer-project-boilerplate) ## Features - **Contract Templates**: Ready-to-use intelligent contract templates and examples - **Testing Framework**: Built-in testing infrastructure for end-to-end testing - **Frontend Integration**: Vue.js-based frontend setup with GenLayerJS integration - **Environment Configuration**: Pre-configured environment setup for development - **Example Implementation**: Full football prediction market implementation ## How it's Built The boilerplate project is structured to provide a development environment for GenLayer applications, combining both backend contract development and frontend user interface. ### Technologies Used - **Python**: For intelligent contract development and testing - **Vue.js**: Frontend framework for building user interfaces - **GenLayerJS**: SDK for interacting with GenLayer contracts - **pytest**: Testing framework for contract validation - **Vite**: Frontend build tool and development server ### Project Structure ``` project-root/ ├── app/ # Frontend application │ ├── src/ # Vue.js source files │ └── .env.example # Frontend environment variables template ├── contracts/ # Intelligent contracts │ └── football_prediction_market.py ├── test/ # Test files └── .env.example # Main environment variables template ``` ## Requirements Before using the GenLayer Project Boilerplate, ensure your system meets the following requirements: - **GenLayer Studio**: Running instance required - **Node.js**: Version 18.x or higher - **Python**: Version 3.8 or higher ### Installation 1. Clone the boilerplate repository: ```bash git clone https://github.com/yeagerai/genlayer-project-boilerplate cd genlayer-project-boilerplate ``` 2. Set up the environment: ```bash cp .env.example .env ``` ## Usage ### Deploying Contracts 1. Access the GenLayer Simulator UI (default: http://localhost:8080) 2. Navigate to "Contracts" section 3. Create a new contract using `/contracts/football_prediction_market.py` 4. Deploy through the "Run and Debug" interface ### Frontend Setup 1. Configure the frontend environment: ```bash cd app cp .env.example .env # Add your contract address to VITE_CONTRACT_ADDRESS ``` 2. Install dependencies and start the development server: ```bash npm install npm run dev ``` ### Running Tests Execute the test suite using pytest: ```bash pip install -r requirements.txt pytest test ``` ## Football Prediction Market Example The included example contract demonstrates a complete prediction market implementation with the following features: ### Contract Functions #### Create Predictions: ```python create_prediction(game_date: str, team1: str, team2: str, predicted_winner: str) ``` #### Resolve Predictions: ```python resolve_prediction(prediction_id: str) ``` #### Query Data: ```python get_player_predictions(player_address: str) get_player_points(player_address: str) ``` ### Frontend Integration The Vue.js frontend demonstrates: - Wallet connection handling - Contract interaction using GenLayerJS - User interface for prediction creation and management - Real-time updates for prediction status ## Testing Framework The boilerplate includes a comprehensive testing suite covering the following scenarios: ### Contract Schema The schema of the contract is well generated and has the expected methods and variables. ### Test Scenarios #### Successful Draw Prediction Tests the scenario where a player correctly predicts a draw between two teams. When the match is resolved as a draw, the player should receive 1 point for their accurate prediction. #### Successful Winner Prediction Validates the case where a player correctly predicts the winning team. Upon match resolution confirming their predicted team as the winner, the player should be awarded 1 point. #### Unsuccessful Prediction Covers the scenario where a player's prediction doesn't match the actual result. This could be: - Predicting Team A wins, but Team B wins - Predicting a draw, but there's a winner - Predicting a winner, but the match ends in a draw In all these cases, the player should receive 0 points. ## Best Practices - Always use environment variables for configuration - Implement comprehensive testing for all contract functions - Follow the provided folder structure for consistency - Use TypeScript for frontend development - Implement proper error handling in both contract and frontend code # developers/decentralized-applications/querying-a-transaction.mdx # Querying a Transaction Reading transactions in GenLayer allows you to inspect the details of any transaction that has been submitted to the network. This is useful for monitoring transaction status, debugging, and verifying transaction details. ## Basic Transaction Reading Here's the simplest way to read a transaction: ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient } from 'genlayer-js'; const client = createClient({ chain: simulator, }); const transactionHash = "0x..."; const transaction = await client.getTransaction({ hash: transactionHash }); ``` {/* ## Transaction Data Structure When you read a transaction, you get access to its complete data structure: ```typescript interface Transaction { hash: `0x${string}` // The unique transaction hash from: `0x${string}` // Address of the sender to: `0x${string}` | null // Address of the recipient (null for contract deployments) nonce: number // Transaction sequence number value: bigint // Amount of native tokens transferred data: `0x${string}` // Transaction input data timestamp: number // Block timestamp when transaction was included status: 'success' | 'failure' | 'pending' // Current transaction status blockNumber: bigint | null // Block number where transaction was included blockHash: `0x${string}` | null // Hash of the block // ... additional fields } ``` ## Reading Different Transaction Types ### Basic Transfer Transaction ```typescript const transferTx = await client.getTransaction({ hash: "0x123...", }); console.log({ from: transferTx.from, to: transferTx.to, value: transferTx.value, status: transferTx.status }); ``` ### Contract Interaction Transaction ```typescript const contractTx = await client.getTransaction({ hash: "0x456...", }); // Decode the transaction input data const decodedInput = client.decodeTransactionInput({ data: contractTx.data, abi: contractABI, // You need the contract's ABI }); console.log({ contractAddress: contractTx.to, functionName: decodedInput.functionName, arguments: decodedInput.args }); ``` ### Contract Deployment Transaction ```typescript const deployTx = await client.getTransaction({ hash: "0x789...", }); console.log({ deployer: deployTx.from, contractAddress: deployTx.creates, // Address of deployed contract deploymentData: deployTx.data }); ``` */} ## Error Handling ```typescript async function getTransactionWithRetry( client: GenLayerClient, hash: string, maxAttempts = 3 ): Promise { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { const tx = await client.getTransaction({ hash }); if (!tx) throw new Error('Transaction not found'); return tx; } catch (error) { if (attempt === maxAttempts) throw error; if (error.message.includes('not found')) { // Wait longer between retries for not found errors await new Promise(resolve => setTimeout(resolve, 2000 * attempt)); continue; } throw error; // Rethrow other errors immediately } } throw new Error('Failed to fetch transaction after max retries'); } ``` ## Monitoring Transaction Status ```typescript async function monitorTransaction( client: GenLayerClient, hash: string, interval = 1000 ): Promise { return new Promise((resolve, reject) => { const checkStatus = async () => { try { const tx = await client.getTransaction({ hash }); if (!tx) { setTimeout(checkStatus, interval); return; } if (tx.status === 'pending') { setTimeout(checkStatus, interval); return; } resolve(tx); } catch (error) { reject(error); } }; checkStatus(); }); } // Usage const finalTx = await monitorTransaction(client, "0x..."); ``` # developers/decentralized-applications/reading-data.mdx # Reading from Intelligent Contracts Reading from an Intelligent Contract allows you to query the contract's state and execute view functions without modifying the blockchain state. These operations are free (no fees) and provide immediate access to contract data. ## Understanding View Operations In GenLayer, functions marked with the `@gl.public.view` decorator are read-only operations that: - Don't modify the contract's state - Can be executed without requiring a transaction - Return data immediately - Don't consume gas - Can be called by any account ## Basic Contract Reading Here's how to read from an Intelligent Contract: ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient, createAccount } from 'genlayer-js'; const account = createAccount(); const client = createClient({ chain: simulator, account: account, }); const result = await client.readContract({ address: contractAddress, functionName: 'get_complete_storage', args: [], }); ``` ### Parameters Explained - `address`: The deployed contract's address on the GenLayer network - `functionName`: The name of the view function you want to call - `args`: An array of arguments that the function accepts (empty if none required) ## Common View Operations Intelligent Contracts typically include several types of view functions: ### State Queries ```typescript // Reading a single value const balance = await client.readContract({ address: contractAddress, functionName: 'get_balance', args: [accountAddress], }); // Reading multiple values const userInfo = await client.readContract({ address: contractAddress, functionName: 'get_user_info', args: [userId], }); ``` ### Computed Values ```typescript // Getting calculated results const totalSupply = await client.readContract({ address: contractAddress, functionName: 'calculate_total_supply', args: [], }); ``` ### Validation Checks ```typescript // Checking permissions const hasAccess = await client.readContract({ address: contractAddress, functionName: 'check_user_permission', args: [userId, 'ADMIN_ROLE'], }); ``` ## Error Handling When reading from contracts, you should handle potential errors: ```typescript try { const result = await client.readContract({ address: contractAddress, functionName: 'get_data', args: [], }); console.log('Data retrieved:', result); } catch (error) { if (error.message.includes('Contract not found')) { console.error('Invalid contract address'); } else if (error.message.includes('Function not found')) { console.error('Invalid function name'); } else { console.error('Error reading contract:', error); } } ``` ## Best Practices 1. **Cache Results**: For frequently accessed data that doesn't change often, consider caching the results. 2. **Batch Readings**: When possible, use functions that return multiple values instead of making multiple separate calls. 3. **Type Safety**: Use TypeScript interfaces to ensure type safety when handling returned data: # developers/decentralized-applications/testing.mdx import { Callout } from 'nextra-theme-docs' # Testing Intelligent Contracts on GenLayer Testing Intelligent Contracts on GenLayer involves deploying contracts, sending transactions, validating their behavior, and identifying issues. Here is some guidance on how to test using the tools provided in the local development environment and GenLayer Studio. ## 1. Testing in the Local Environment For a more advanced and controlled testing setup, you can leverage the GenLayer Project Boilerplate and the provided test helpers. Please note that you need the Studio running to run the tests by sending requests to the it. ### Testing Workflow #### 1. Create Accounts Use the `create_new_account` helper to generate accounts for testing. These accounts simulate users interacting with the contract. ```python from tools.request import create_new_account account = create_new_account() ``` #### 2. Set Up Validators Validators are essential for processing transactions in GenLayer. Use the `sim_createRandomValidators` method to initialize them. ```python from tools.request import payload, post_request_localhost validators_response = post_request_localhost( payload("sim_createRandomValidators", 5, 8, 12, ["openai"], ["gpt-4o"]) ).json() ``` #### 3. Deploy the Contract Deploy your Intelligent Contract using the `deploy_intelligent_contract` helper: ```python from tools.request import deploy_intelligent_contract contract_code = open("contracts/my_contract.py", "r").read() contract_address, deploy_response = deploy_intelligent_contract(account, contract_code, "{}") ``` #### 4. Interact with the Contract Use `send_transaction` for writing data to the contract and `call_contract_method` for reading data: ```python from tools.request import send_transaction, call_contract_method # Write data send_transaction(account, contract_address, "method_name", [arg1, arg2]) # Read data result = call_contract_method(contract_address, account, "get_state", []) ``` #### 5. Assertions Validate the responses using provided assertion helpers: ```python from tools.response import assert_dict_struct, has_success_status assert has_success_status(result) assert_dict_struct(result, expected_structure) ``` #### 6. Clean Up After completing the tests, delete the validators or reset the environment: ```python delete_response = post_request_localhost(payload("sim_deleteAllValidators")).json() ``` # developers/decentralized-applications/writing-data.mdx # Writing to Intelligent Contracts Writing to an Intelligent Contract involves sending transactions that modify the contract's state. Unlike read operations, write operations require fees and need to be processed by the network before taking effect. ## Understanding Write Operations In GenLayer, functions that modify state: - Require a transaction to be sent to the network - Consume gas (computational resources) - Need time to be processed and finalized - Must be signed by an account with sufficient balance to pay for the transaction fees - Return a transaction hash immediately, but state changes are not instant ## Basic Contract Writing Here's how to write to an Intelligent Contract: ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient, createAccount } from 'genlayer-js'; import type { TransactionStatus } from 'genlayer-js/types'; const account = createAccount(); const client = createClient({ chain: simulator, account: account, }); // Send the transaction const transactionHash = await client.writeContract({ address: contractAddress, functionName: 'update_storage', args: ['new_data'], value: 0, // Optional: amount of native GEN tokens to send }); // Wait for the transaction to be processed const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.FINALIZED, // or 'ACCEPTED' }); ``` ### Parameters Explained - `address`: The deployed contract's address - `functionName`: The name of the function to call - `args`: Array of arguments for the function - `value`: Amount of native tokens to send (in wei) ## Transaction Lifecycle 1. **Transaction Creation** ```typescript const transactionHash = await client.writeContract({ address: contractAddress, functionName: 'mint_token', args: [recipient, amount], }); ``` 2. **Transaction Status Monitoring** ```typescript // Basic waiting const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: 'FINALIZED', }); // Advanced monitoring with timeout const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: 'FINALIZED', interval: 5_000, // check every 5 seconds retries: 10, // maximum number of retries }); ``` ## Common Write Operations ### Token Transfers ```typescript // Sending tokens const hash = await client.writeContract({ address: tokenContractAddress, functionName: 'transfer', args: [recipientAddress, amount], }); ``` ### State Updates ```typescript // Updating user data const hash = await client.writeContract({ address: contractAddress, functionName: 'update_user_profile', args: [userId, newProfile], }); ``` ## Error Handling ```typescript try { const hash = await client.writeContract({ address: contractAddress, functionName: 'update_data', args: ['new_data'], }); try { const receipt = await client.waitForTransactionReceipt({ hash, status: 'FINALIZED', }); console.log('Transaction successful:', receipt); } catch (waitError) { console.error('Transaction failed or timed out:', waitError); } } catch (error) { if (error.message.includes('insufficient funds')) { console.error('Not enough balance to pay for transaction'); } else if (error.message.includes('user rejected')) { console.error('User rejected the transaction'); } else { console.error('Error sending transaction:', error); } } ``` ## Transaction Status Types GenLayer transactions can have different status requirements: ```typescript enum TransactionStatus { PENDING = "PENDING", CANCELED = "CANCELED", PROPOSING = "PROPOSING", COMMITTING = "COMMITTING", REVEALING = "REVEALING", ACCEPTED = "ACCEPTED", FINALIZED = "FINALIZED", UNDETERMINED = "UNDETERMINED", } // Wait for just acceptance (faster) const acceptedReceipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.ACCEPTED, }); // Wait for full finalization const finalizedReceipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.FINALIZED, }); ``` ## Best Practices 1. **Always Wait for Receipts**: Don't assume a transaction is successful just because you got a hash. 2. **Handle Timeouts**: Set appropriate timeouts for transaction waiting. 3. **Implement Retry Logic**: For important transactions, implement retry mechanisms: ```typescript async function sendWithRetry( client: GenLayerClient, params: WriteContractParameters, maxAttempts = 3 ): Promise { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { const hash = await client.writeContract(params); return await client.waitForTransactionReceipt({ hash, status: 'FINALIZED', timeout: 30_000 * attempt, // Increase timeout with each attempt }); } catch (error) { if (attempt === maxAttempts) throw error; console.log(`Attempt ${attempt} failed, retrying...`); await new Promise(resolve => setTimeout(resolve, 1000 * attempt)); } } throw new Error('Max retry attempts reached'); } ``` # developers/intelligent-contracts/advanced-features/contract-to-contract-interaction.mdx import { Callout } from 'nextra-theme-docs' # Contract-to-Contract Interaction Contract-to-Contract Interaction in GenLayer allows developers to create more complex and modular Intelligent Contracts by enabling communication between them. This feature is crucial for building scalable and composable decentralized applications, allowing contracts to read from and write to other contracts. Please note that this feature is in progress and will be subject to changes in the near future. ## Features of Contract-to-Contract Interaction The Contract-to-Contract Interaction provides several powerful capabilities: #### 1. Cross-Contract Reads Contracts can read data from other contracts, allowing for the sharing of state and information across different parts of your application. #### 2. Cross-Contract Writes Contracts can initiate state changes in other contracts, enabling complex multi-step operations that span multiple contracts. #### 3. Modular Design By separating concerns into different contracts, developers can create more maintainable and upgradable systems. #### 4. Composability Contracts can be designed to work together, creating more powerful and flexible applications by combining different functionalities. ## How to Use Contract-to-Contract Interaction in Your Contracts As GenLayer calldata is dynamically typed users can send whatever they want to a contract, or use statically typed interface to facilitate type checking and autocompletion Exact parameters of `.view()` and `.write()` are subject to change ### Dynamically typed approach ```py address = Address("0x03FB09251eC05ee9Ca36c98644070B89111D4b3F") result = gl.ContractAt(address).view().method_name(1, '234') gl.ContractAt(address).write(gas=10**5).method_name(1, '234') # ^ write methods do not return anything! ``` ### Statically typed approach ```py @gl.contract_interface class GenLayerContractIface: class View: def method_name(self, a: int, b: str): ... class Write: pass ### in your contract method ### address = Address("0x03FB09251eC05ee9Ca36c98644070B89111D4b3F") result = GenLayerContractIface(address).view().method_name(1, '234') ``` ## Methods for Contract-to-Contract Interaction #### 1. Reading from Another Contract To read data from another contract, create an instance of the `Contract` class and call its methods: ```python filename="token_interaction" copy token_contract = gl.ContractAt(self.token_contract_address) balance = token_contract.view().get_balance_of(account_address) ``` #### 2. Writing to Another Contract To initiate a state change in another contract, call a method that modifies its state: ```python filename="token_interaction" copy token_contract = gl.ContractAt(self.token_contract_address) success = token_contract.emit(gas=100000).transfer(to_address, amount) ``` #### 3. Handling Multiple Contract Interactions For more complex scenarios involving multiple contracts: ```python filename="multi_contract_interaction" copy @gl.contract class MultiContractInteraction: token_contract: Address storage_contract: Address def __init__(self, token_contract: str, storage_contract: str): self.token_contract = Address(token_contract) self.storage_contract = Address(storage_contract) @gl.public.write def complex_operation(self, account: str, amount: int, data: str) -> bool: token = gl.ContractAt(self.token_contract) storage = gl.ContractAt(self.storage_contract) # Read from token contract balance = token.view().get_balance_of(account) if balance >= amount: # Write to token contract token.emit(gas=100000).transfer(self.address, amount) # Write to storage contract storage.emit(gas=100000).store_data(account, data) return True return False ``` ## Interacting with Ghost Contracts Eth contracts have statically typed calldata format, which means that only statically typed approach with interfaces is applicable This is not supported in the Studio right now ```py @gl.ghost_contract class GhostContractIface: class View: def method_name(self, param: str, /) -> tuple[u32, str]: ... class Write: def bar(self, param: str, /): ... ### in your contract method ### address = Address("0x03FB09251eC05ee9Ca36c98644070B89111D4b3F") i, s = GhostContractIface(address).view().method_name('234') ``` ## Best Practices for Contract-to-Contract Interaction 1. **Security**: Always validate inputs and check permissions before allowing cross-contract interactions. 2. **Error Handling**: Implement proper error handling for cases where called contracts might revert or throw exceptions. 3. **Upgradability**: Consider using upgradable patterns if you need to change contract interactions in the future. 4. **Testing**: Thoroughly test all contract interactions, including edge cases and potential vulnerabilities. # developers/intelligent-contracts/advanced-features/vector-store.mdx # Vector Store The Vector Store feature in GenLayer allows developers to enhance their Intelligent Contracts by efficiently storing, retrieving, and calculating similarities between texts using vector embeddings. This feature is particularly useful for tasks that require natural language processing (NLP), such as creating context-aware applications or indexing text data for semantic search. ## Key Features of Vector Store The Vector Store provides several powerful features for managing text data: #### 1. Text Embedding Storage You can store text data as vector embeddings, which are mathematical representations of the text, allowing for efficient similarity comparisons. Each stored text is associated with a vector and metadata. #### 2. Similarity Calculation The Vector Store allows you to calculate the similarity between a given text and stored vectors using cosine similarity. This is useful for finding the most semantically similar texts, enabling applications like recommendation systems or text-based search. #### 3. Metadata Management Along with the text and vectors, you can store additional metadata (any data type) associated with each text entry. This allows developers to link additional information (e.g., IDs or tags) to the text for retrieval. #### 4. CRUD Operations The Vector Store provides standard CRUD (Create, Read, Update, Delete) operations, allowing developers to add, update, retrieve, and delete text and vector entries efficiently. ## How to Use Vector Store in Your Contracts To use the Vector Store in your Intelligent Contracts, you will interact with its methods to add and retrieve text data, calculate similarities, and manage vector storage. Below are the details of how to use this feature. #### Importing Vector Store First, import the VectorStore class from the standard library in your contract: ```python from backend.node.genvm.std.vector_store import VectorStore ``` #### Creating a Contract with Vector Store Here’s an example of a contract using the Vector Store for indexing and searching text logs: ```python # { # "Seq": [ # { "Depends": "py-lib-genlayermodelwrappers:test" }, # { "Depends": "py-genlayer:test" } # ] # } from genlayer import * import genlayermodelwrappers import numpy as np from dataclasses import dataclass @dataclass class StoreValue: log_id: u256 text: str # contract class @gl.contract class LogIndexer: vector_store: VecDB[np.float32, typing.Literal[384], StoreValue] def __init__(self): pass def get_embedding_generator(self): return genlayermodelwrappers.SentenceTransformer("all-MiniLM-L6-v2") def get_embedding( self, txt: str ) -> np.ndarray[tuple[typing.Literal[384]], np.dtypes.Float32DType]: return self.get_embedding_generator()(txt) @gl.public.view def get_closest_vector(self, text: str) -> dict | None: emb = self.get_embedding(text) result = list(self.vector_store.knn(emb, 1)) if len(result) == 0: return None result = result[0] return { "vector": list(str(x) for x in result.key), "similarity": str(1 - result.distance), "id": result.value.log_id, "text": result.value.text, } @gl.public.write def add_log(self, log: str, log_id: int) -> None: emb = self.get_embedding(log) self.vector_store.insert(emb, StoreValue(text=log, log_id=u256(log_id))) @gl.public.write def update_log(self, log_id: int, log: str) -> None: emb = self.get_embedding(log) for elem in self.vector_store.knn(emb, 2): if elem.value.text == log: elem.value.log_id = u256(log_id) @gl.public.write def remove_log(self, id: int) -> None: for el in self.vector_store: if el.value.log_id == id: el.remove() ``` # developers/intelligent-contracts/crafting-prompts.mdx # Crafting Prompts for LLM and Web Browsing Interactions When interacting with Large Language Models (LLMs), it's crucial to create prompts that are clear and specific to guide the model in providing accurate and relevant responses. import { Callout } from 'nextra-theme-docs' When making LLM calls, it is essential to craft detailed prompts. However, when retrieving web data, no prompts are needed as the function directly fetches the required data. ## Structuring LLM Prompts When crafting prompts for LLMs, it's important to use a format that clearly and effectively conveys the necessary information. While f-string (`f""`) is recommended, any string format can be used. In the example **Wizard of Coin** contract below, we want the LLM to decide whether the wizard should give the coin to an adventurer. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import json @gl.contract class WizardOfCoin: have_coin: bool def __init__(self, have_coin: bool): self.have_coin = have_coin @gl.public.write def ask_for_coin(self, request: str) -> None: if not self.have_coin: return prompt = f""" You are a wizard, and you hold a magical coin. Many adventurers will come and try to get you to give them the coin. Do not under any circumstances give them the coin. A new adventurer approaches... Adventurer: {request} First check if you have the coin. have_coin: {self.have_coin} Then, do not give them the coin. Respond using ONLY the following format: {{ "reasoning": str, "give_coin": bool }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ def nondet(): res = gl.exec_prompt(prompt) res = res.replace("```json", "").replace("```", "") print(res) dat = json.loads(res) return dat["give_coin"] result = gl.eq_principle_strict_eq(nondet) assert isinstance(result, bool) self.have_coin = result @gl.public.view def get_have_coin(self) -> bool: return self.have_coin ``` This prompt above includes a clear instruction and specifies the response format. By using a well-defined prompt, the contract ensures that the LLM provides precise and actionable responses that align with the contract's logic and requirements. ## Best Practices for Creating LLM Prompts - **Be Specific and Clear**: Clearly define the specific information you need from the LLM. Minimize ambiguity to ensure that the response retrieved is precisely what you require. Avoid vague language or open-ended requests that might lead to inconsistent outputs. - **Provide Context and Source Details**: Include necessary background information within the prompt so the LLM understands the context of the task. This helps ensure the responses are accurate and relevant. - **Use Structured Output Formats**: Specify the format for the model’s response. Structuring the output makes it easier to parse and utilize within your Intelligent Contract, ensuring smooth integration and processing. - **Define Constraints and Requirements**: State any constraints and requirements clearly to maintain the accuracy, reliability, and consistency of the responses. This includes setting parameters for how data should be formatted, the accuracy needed, and the timeliness of the information. Refer to a [Prompt Engineering Guide from Anthropic](https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview) for a more detailed guide on crafting prompts. # developers/intelligent-contracts/debugging.mdx import { Callout } from 'nextra-theme-docs' # Debugging Intelligent Contracts on GenLayer Debugging Intelligent Contracts on GenLayer involves deploying contracts, sending transactions, validating their behavior, and identifying issues using logs. Here is some guidance on how to debug using the GenLayer Studio. ## 2. Debugging in GenLayer Studio When testing in GenLayer Studio, you can debug issues by examining the logs and outputs. The Studio provides detailed logs for every transaction and contract execution. ### Getting static code syntax errors If you get a syntax error in your contract, you can see the error on a red panel in the Studio in the **Run and Debug** tab. Here is an example of a syntax error in line 42 of the Wizard of Coin contract: ![Syntax Error](/studio/syntax-error.png) ### Viewing Logs #### Access Logs The logs are located in the bottom section of the Studio in the **Run and Debug** tab. #### Filter Relevant Logs Use filters to isolate logs related to specific transactions or contracts. You can select the debug level (info, success, error), the execution layer(RPC Server, GenVM, and Consensus), and the transaction hash. Also, you can select a transaction from the left list and see the logs for that specific transaction. ### Identifying Common Issues #### Input Validation Errors - Look for incorrect or missing parameters in the transaction payload #### Contract Logic Errors - Debug issues in contract logic by examining state changes and variable values in logs #### Non-deterministic Output Issues - Analyze LLM or web data interactions for discrepancies or timeouts #### Consensus Errors - Investigate validator disagreements or timeout errors to identify potential misconfigurations # developers/intelligent-contracts/equivalence-principle.mdx import { Callout } from 'nextra-theme-docs' # Managing Intelligent Contract Operations with the Equivalence Principle The Equivalence Principle is a core concept in GenLayer's Intelligent Contract framework. It ensures consistency and reliability when handling non-deterministic operation results, such as responses from Large Language Models or web data retrieval, by establishing a standard for validators to agree on the correctness of these outputs. These functions give users detailed control over how the outputs are validated. Depending on how you want the validators to work, you can choose from a few options, such as a principle that uses LLMs or one that just uses a strict comparison. Advanced users may also choose to write their own equivalence principle The Equivalence Principle involves multiple validators randomly selected to determine whether different outputs from non-deterministic operations can be considered equivalent. One validator acts as the leader, proposing the output, while others validate it and then return it instead of their computation. ## Equivalence Principles Options Validators work to reach a consensus on whether the result set by the leader is acceptable, which might involve direct comparison or qualitative evaluation, depending on the contract's design. If the validators do not reach a consensus due to differing data interpretations or an error in data processing, the transaction will become undetermined. ### Comparative Equivalence Principle In the Comparative Equivalence Principle, the leader and the validators perform identical tasks and then directly compare their respective results with the predefined criteria to ensure consistency and accuracy. This method uses an acceptable margin of error to handle slight variations in results between validators and is suitable for quantifiable outputs. However, computational demands and associated costs increase since multiple validators perform the same tasks as the leader. ```python gl.eq_principle_prompt_comparative( your_non_deterministic_function, "The result must not differ by more than 5%" ) ``` For example, if an intelligent contract is tasked with fetching the follower count of a Twitter account and the Equivalence Principle specifies that _follower counts should not differ by more than 5%_, validators will compare their results to the leader's result utilizing their own LLMs to ensure they fall within this margin. ### Non-Comparative Equivalence Principle GenLayer SDK provides function `gl.eq_principle_prompt_non_comparative` for handling most scenarios that require performing subjective NLP tasks #### Non-Comparative Equivalence Principle Parameters The `eq_principle_prompt_non_comparative` function takes three key parameters that define how validators should evaluate non-deterministic operations: 1. **input** (function) The input parameter represents the original data or function that needs to be processed by the task. For instance, when building a sentiment analysis contract, the input might be a text description that needs to be classified. The function processes this input before passing it to the validators for evaluation. 2. **task** (str) The task parameter provides a clear and concise instruction that defines exactly what operation needs to be performed on the input. This string should be specific enough to guide the validators in their evaluation process while remaining concise enough to be easily understood. For example, in a sentiment analysis context, the task might be "Classify the sentiment of this text as positive, negative, or neutral". This instruction serves as a guide for both the leader and validators in processing the input. 3. **criteria** (str) The criteria parameter defines the specific rules and requirements that validators use to determine if an output is acceptable. This string should contain a comprehensive set of validation parameters that ensure consistency across different validators. While the criteria can be structured in various ways, it typically outlines the expected format of the output and any specific considerations that should be taken into account during validation. For example: ```python criteria = """ Output must be one of: positive, negative, neutral Consider context and tone Account for sarcasm and idioms """ ``` This criteria helps validators make consistent decisions about whether to accept or reject the leader's proposed output, even when dealing with subjective or non-deterministic results. #### Example Usage ```python @gl.contract class SentimentAnalyzer: @gl.public.write def analyze_sentiment(self, text: str) -> str: self.sentiment = gl.eq_principle_prompt_non_comparative( input=text, task="Classify the sentiment of this text as positive, negative, or neutral", criteria=""" Output must be one of: positive, negative, neutral Consider context and tone Account for sarcasm and idioms """ ) ``` In this example: - `input` is the text to analyze - `task` defines what operation to perform - `criteria` ensures consistent validation across validators without requiring exact output matching #### Data flow ```mermaid graph TD task[task & criteria] input[input function] subgraph Leader input_leader[executing input function] leader["performing task (llm)"] input_leader --> leader end task --> leader leader --> output subgraph Validator input_validator[executing input function] validator["validating (llm)"] input_validator --> validator end task --> validator output --> validator input --> input_leader input --> input_validator output --> final_result validator -..- final_result ``` # developers/intelligent-contracts/error-handling.mdx import { Callout } from 'nextra-theme-docs' # Error handling Sometimes contracts can produce errors. There are two kinds of errors in GenVM: - unrecoverable errors - rollbacks If a non-deterministic block or contract call produces an unrecoverable error, it will terminate your contract execution. Unrecoverable errors include: - `exit(x)` where $x \neq 0$ - unhandled `Exception` And a recoverable error via one of two mechanisms: - `raise Rollback("message")` - `gl.rollback_immediate("message")` Later method won't unwind stack and current VM can't catch it Built-in `gl.eq_principle_*` functions family will `raise Rollback(sub_vm_message)` in case non-deterministic block agreed on a rollback. Note that rollback message is compared for strict equality # developers/intelligent-contracts/examples/adr-validator.mdx import Image from 'next/image' import { Callout } from 'nextra-theme-docs' # ADRValidator Contract The ADRValidator contract sets up a system for validating, categorizing, and ensuring consistency of Architectural Decision Records (ADRs) in a decentralized and automated manner. This contract demonstrates complex document validation, category management, and a reward system within a blockchain environment. This intelligent contract is currently not migrated to the real GenVM syntaxis. ```python import json import re from backend.node.genvm.icontract import IContract from backend.node.genvm.equivalence_principle import call_llm_with_principle class ADRValidator(IContract): def __init__(self): self.owner = contract_runner.from_address self.arch_categories = {} self.balances = {} self.max_reward = 10 def change_owner(self, new_owner: str): if contract_runner.from_address == self.owner: self.owner = new_owner def set_max_reward(self, new_max_reward: int): if contract_runner.from_address == self.owner: self.max_reward = new_max_reward def get_owner(self) -> str: return self.owner def get_categories(self) -> str: return { category: details["description"] for category, details in self.arch_categories.items() } def get_adrs_of_a_category(self, category_name: str) -> dict: if category_name in self.arch_categories: return self.arch_categories[category_name]["ADRs"] def get_balances(self) -> dict[str, int]: return self.balances def get_balance_of(self, address: str) -> int: return self.balances.get(address, 0) def add_category(self, category_name: str, category_description: str): if ( contract_runner.from_address == self.owner and category_name not in self.arch_categories ): self.arch_categories[f"{category_name}"] = { "description": category_description, "ADRs": [], } async def validate_adr(self, adr: str, category_name: str) -> None: print("validate") if not self._check_template(adr): return output = await self._evaluate_adr(adr, category_name) ## Improvement: would split checks more by concern if not output["accepted"]: return if contract_runner.from_address not in self.balances: self.balances[contract_runner.from_address] = 0 self.balances[contract_runner.from_address] += output["reward"] self.arch_categories[category_name]["ADRs"].append(adr) def _check_template(self, adr: str) -> bool: adr = adr.replace("\r\n", "\n").replace("\r", "\n") pattern = r"^\# [^\n]+?\n+(- Status: (proposed|accepted|validated).+)\n+(- Deciders: [^\n]+)\n+(- Date: \d\d\d\d-\d\d-\d\d)\n+(\#\# Context and Problem Statement)\n+(\#\#\#\# Problem\n+(.|\n)*)+(\#\#\#\# Context\n+(.|\n)*)+(\#\# Decision Drivers+(.|\n)*)+(\#\# Considered Options+(.|\n)*)+(\#\# Decision Outcome+(.|\n)*)+(\#\#\# Consequences+(.|\n)*)+(\#\# Pros and Cons of the Options+(.|\n)*)+(\#\#\#(.|\n)*)+(\#\#\#\# Pros+(.|\n)*)+(\#\#\#\# Cons+(.|\n)*)+(\#\#\#(.|\n)*)+(\#\#\#\# Pros+(.|\n)*)+(\#\#\#\# Cons+(.|\n)*)" compiled_pattern = re.compile(pattern, re.MULTILINE | re.DOTALL) result = bool(compiled_pattern.match(adr)) print("Result of checking template structure: ", result) return result async def _evaluate_adr(self, adr: str, category: str) -> object: print("Evaluating ADR...") valid_decisions = False prompt = f""" Here are some architecture decisions made in the past, and a new decision candidate. You must check past decisions for contradiction with the new candidate that would block this candidate from being added to ADRs. - Past decisions: {self.arch_categories[category]['ADRs']} - New decision candidate: {adr} You must decide if the new decision can be accepted or if it should be rejected. In case of rejection: - You MUST provide a REASON for the rejection. In case of acceptance: - The REASON should be an EMPTY STRING. - You MUST decide of a REWARD (INTEGER) between 1 and {self.max_reward}. Evaluate the reward based on the potential impact, importance, and writing quality of the candidate. Respond ONLY with the following format: {{ "accepted": bool, "reasoning": str, "reward": int, }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ result = await call_llm_with_principle( prompt, eq_principle="The result['accepted'] has to be exactly the same", ) result_clean = result.replace("True", "true").replace("False", "false") output = json.loads(result_clean) print(output) return output ``` ## Code Explanation - **Initialization**: The `ADRValidator` class initializes with an owner, empty categories and balances, and a default max reward. - **Key Methods**: - `validate_adr()`: Validates an ADR's structure and content, and rewards the submitter if accepted. - `_check_template()`: Uses regex to ensure the ADR follows a specific structure. - `_evaluate_adr()`: Uses an LLM to check for contradictions with existing ADRs and determine acceptance and reward. - **Management Methods**: Methods for changing owner, setting max reward, and managing categories. - **Read Methods**: Various getter methods to retrieve contract state, categories, and balances. ## Deploying the Contract To deploy the ADRValidator contract: 1. **Deploy the Contract**: No initial parameters are needed. The deployer becomes the initial owner. ## Checking the Contract State After deploying the contract, you can check its state in the Read Methods section: - Use `get_owner()` to see the current contract owner. - Use `get_categories()` to view defined architectural categories. - Use `get_balances()` to check reward balances of contributors. ## Executing Transactions To interact with the deployed contract, go to the Write Methods section. Here, you can: - Call `add_category(name, description)` to define new architectural categories (owner only). - Call `validate_adr(adr, category_name)` to submit an ADR for validation. - Call `change_owner(new_owner)` or `set_max_reward(new_max_reward)` for contract management (owner only). ## Analyzing the Contract's Behavior The contract's behavior involves several complex processes: 1. **Template Validation**: Uses regex to ensure ADRs follow a specific structure. 2. **Consistency Checking**: Employs an LLM to compare new ADRs against existing ones for contradictions. 3. **Automated Decision-Making**: Determines acceptance and reward based on LLM evaluation. 4. **Reward System**: Automatically credits submitters with tokens for accepted ADRs. ## Handling Different Scenarios As illustrated in the provided flowchart: ADRValidator Flowchart - **Invalid ADR Structure**: The ADR is rejected without further evaluation. - **Valid ADR, Contradictions Found**: The ADR is rejected with reasoning provided. - **Valid ADR, No Contradictions**: The ADR is accepted, and the submitter is rewarded. The outputs shows various scenarios: ADRValidator Outputs This diagram illustrates different outcomes based on the ADR's content and its relation to existing ADRs in the category. ## Use Cases and Market Potential The ADRValidator contract has broad applications: - **Software Development Teams**: For managing and validating architectural decisions. - **Resource Allocation**: In contexts where decisions about shared resources (e.g., budget, design principles) are critical. - **Hackathons and Competitions**: As a tool for evaluating and rewarding contributions. Its automated, trustless nature makes it valuable for any organization seeking to streamline decision-making processes and ensure consistency in architectural choices. ## Future Enhancements Future developments may include: 1. **Spam Prevention**: Implementing measures to prevent submission of fake or spammy ADRs. 2. **Platform Integration**: Direct integration with platforms like GitHub for seamless ADR management. 3. **Global ADR Repository**: Evolving into a comprehensive, accessible repository for ADRs worldwide. This ADRValidator contract demonstrates an innovative use of GenLayer for document validation and decision-making in software architecture. It showcases how Intelligent Contracts can automate complex processes, ensure consistency, and provide incentives for quality contributions in a decentralized manner. # developers/intelligent-contracts/examples/flight-insurance.mdx import { Callout } from 'nextra-theme-docs' # Flight Insurance Contract The Flight Insurance contract sets up a scenario for managing flight delay insurance. It allows passengers to buy insurance for specific flights and automatically processes claims based on flight status information from an independent source. This contract demonstrates complex real-world interactions, external data integration, and automated claim processing within a blockchain environment. This intelligent contract is currently not migrated to the real GenVM syntaxis. ```python import json from backend.node.genvm.icontract import IContract from backend.node.genvm.equivalence_principle import EquivalencePrinciple # Flight Insurance Intelligent Contract is a contract that allows passengers to buy insurance for their flights. # The contract is created by the insurance manager for specific flight # and the passengers can buy insurance for this specific flight. # The contract has a method to check the flight status from an independent source of information # and a method to claim the insurance in case the flight is delayed. # The payment is done by the insurance manager to the passengers in case the flight is delayed. # Passenger does not need to trust on the insurance manager to get the payment. class FlightInsurance(IContract): def __init__(self, _flight_number: str, _flight_date: str, _flight_time: str, _flight_from: str, _flight_to: str, _num_passengers_paid_insurance: int, _insurance_value_per_passenger: int): self.flight_number = _flight_number self.num_passengers_paid_insurance = _num_passengers_paid_insurance self.flight_arrival_delayed = False self.flight_date = _flight_date self.flight_time = _flight_time self.flight_from = _flight_from self.flight_to = _flight_to self.resolution_url = "https://flightaware.com/live/flight/" + self.flight_number + "/history/" self.resolution_url = self.resolution_url + self.flight_date + "/" + self.flight_time + "/" self.resolution_url = self.resolution_url + self.flight_from + "/" + self.flight_to self.loss_payment_value_per_passenger = _insurance_value_per_passenger self.balances = {} self.balances[contract_runner.from_address] = _num_passengers_paid_insurance*_insurance_value_per_passenger self.insurance_manager = contract_runner.from_address # Example of constructor with hardcoded values to save time in the testing # def __init__(self): # self.flight_number = "TAP457" # self.num_passengers_paid_insurance = 35 # self.flight_arrival_delayed = False # self.flight_date = "20240818" # self.flight_time = "0510Z" # self.flight_from = "LFPO" # self.flight_to = "LPPR" # self.resolution_url = "https://flightaware.com/live/flight/" + self.flight_number + "/history/" # self.resolution_url = self.resolution_url + self.flight_date + "/" + self.flight_time + "/" # self.resolution_url = self.resolution_url + self.flight_from + "/" + self.flight_to # self.loss_payment_value_per_passenger = 30 # self.balances = {} # self.balances[contract_runner.from_address] = self.loss_payment_value_per_passenger*self.loss_payment_value_per_passenger # self.insurance_manager = contract_runner.from_address async def check_flight_status(self) -> None: """Check the flight status from an external source.""" print(f"Checking flight status: {self.resolution_url}") final_result = {} async with EquivalencePrinciple( result=final_result, principle="The arrival status should be consistent", comparative=True, ) as eq: web_data = await eq.get_webpage(self.resolution_url) print(" ") print("web_data: ") print(web_data) print(" ") print(" ") prompt = f""" In the following web page, find if the flight arrival was late or not: Web page content: {web_data} End of web page data. Respond using ONLY the following format: {{ "arrivalstatus": bool // True if the flight arrival was delayed or False if it was on time }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ result = await eq.call_llm(prompt) print("********************************") print("result: ") print(result) print("================================") result_clean = result.replace("True", "true").replace("False", "false") print("********************************") print("result_clean: ") print(result_clean) print("================================") eq.set(result_clean) output = json.loads(result_clean) print("********************************") print("output: ") print(output["arrivalstatus"]) print("================================") if output["arrivalstatus"] is True: self.flight_arrival_delayed = True print("********************************") print("flight_arrival_delayed: ") print(self.flight_arrival_delayed) print("================================") def add_passenger(self, _passenger_address:str) ->None: self.balances[_passenger_address] = 0 def insurance_claim(self, _passenger_address:str) ->None: if self.flight_arrival_delayed is True: if _passenger_address in self.balances: if self.balances[_passenger_address] == 0: self.balances[_passenger_address] = self.loss_payment_value_per_passenger self.balances[self.insurance_manager] = (self.balances[self.insurance_manager]-self.loss_payment_value_per_passenger) def get_flight_status(self) ->bool: return self.flight_arrival_delayed def get_insurance_balance(self, _passenger_address:str) ->int: if _passenger_address in self.balances: return self.balances[_passenger_address] else: return 0 def get_insurance_manager_balance(self) ->int: return self.balances[self.insurance_manager] def get_insurance_manager(self) ->str: return self.insurance_manager def get_flight_number(self) ->str: return self.flight_number def get_flight_date(self) ->str: return self.flight_date def get_flight_time(self) ->str: return self.flight_time def get_flight_from(self) ->str: return self.flight_from def get_flight_to(self) ->str: return self.flight_to def get_resolution_url(self) ->str: return self.resolution_url def get_loss_payment_value_per_passenger(self) ->int: return self.loss_payment_value_per_passenger def get_num_passengers_paid_insurance(self) ->int: return self.num_passengers_paid_insurance ``` ## Code Explanation - **Initialization**: The FlightInsurance class initializes the contract with specific flight details, insurance parameters, and initial balances. - **Key Methods**: - `ask_for_flight_status()`: Checks the flight status from an external source (FlightAware) using an LLM to interpret the data. - `add_passenger()`: Adds a new passenger to the insurance contract. - `insurance_claim()`: Processes insurance claims for passengers if the flight is delayed. - **Read Methods**: Various getter methods to retrieve flight details, insurance parameters, and balances. ## Deploying the Contract To deploy the Flight Insurance contract, you need to provide the flight details and insurance parameters: 1. **Set Flight Details**: Provide flight number, date, time, origin, and destination. 2. **Set Insurance Parameters**: Specify the number of insured passengers and the insurance value per passenger. 3. **Deploy the Contract**: Once all parameters are set, deploy the contract to start the insurance coverage. ## Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. - Use `get_flight_status()` to see if the flight is delayed. - Use `get_insurance_balance(address)` to check a passenger's insurance balance. - Use other getter methods to retrieve various contract details. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can: - Call `ask_for_flight_status()` to update the flight status from the external source. - Call `add_passenger(address)` to add a new insured passenger. - Call `insurance_claim(address)` for a passenger to claim their insurance if the flight is delayed. ## Analyzing the Contract's Behavior The contract's behavior involves several complex interactions: - **External Data Integration**: The contract uses an LLM to interpret flight status data from FlightAware, an external source. - **Automated Claim Processing**: If a flight is determined to be delayed, the contract automatically processes claims for insured passengers. - **Balance Management**: The contract manages balances for both the insurance manager and insured passengers, automatically transferring funds when claims are processed. ## Handling Different Scenarios - **Flight On Time**: If the flight is on time, no claims are processed, and balances remain unchanged. - **Flight Delayed**: If the flight is delayed, insured passengers can claim their insurance, and funds are automatically transferred from the insurance manager's balance to the passengers'. - **Multiple Claims**: The contract ensures that each passenger can only claim once, preventing double-dipping. - **New Passengers**: The contract allows adding new passengers, expanding the pool of insured individuals. This Flight Insurance contract demonstrates a practical use case for blockchain technology in the insurance industry. It showcases how smart contracts can automate complex processes, integrate external data sources, and provide transparent, trustless insurance services. The use of an LLM to interpret external data adds an innovative layer of intelligence to the contract's decision-making process. # developers/intelligent-contracts/examples/genlayer-dao.mdx import { Callout } from 'nextra-theme-docs' # GenLayerDAO Contract The GenLayerDAO contract implements a robust Decentralized Autonomous Organization (DAO) with built-in governance mechanisms and a bounty system. This contract demonstrates complex decision-making processes, token-based voting, and AI-assisted proposal evaluation within a blockchain environment. This intelligent contract is currently not migrated to the real GenVM syntaxis. ```python import json from backend.node.genvm.icontract import IContract from backend.node.genvm.equivalence_principle import call_llm_with_principle # Custom exception classes for GenLayerDAO class DAOException(Exception): """Base exception class for GenLayerDAO""" pass class InsufficientTokensException(DAOException): """Exception raised when a user doesn't have enough tokens""" pass class InvalidBountyException(DAOException): """Exception raised for invalid bounty operations""" pass class VotingException(DAOException): """Exception raised for voting-related issues""" pass class InvalidInputException(DAOException): """Exception raised for invalid input parameters""" pass class Bounty: """ Represents a bounty in the GenLayerDAO system. Attributes: id (int): Unique identifier for the bounty description (str): Detailed description of the bounty reward_description (str): Description of the reward for completing the bounty proposer (str): Address of the user who proposed the bounty votes_for (int): Number of votes in favor of the bounty votes_against (int): Number of votes against the bounty status (str): Current status of the bounty ("proposed", "active", or "completed") submissions (list): List of submissions for the bounty vote_snapshot (dict): Snapshot of token balances at proposal time has_voted (dict): Tracks which users have voted on the bounty """ def __init__(self, id: int, description: str, reward_description: str, proposer: str): self.id = id self.description = description self.reward_description = reward_description self.proposer = proposer self.votes_for = 0 self.votes_against = 0 self.status = "proposed" # Can be "proposed", "active", or "completed" self.submissions: list[dict[str, str | bool]] = [] self.vote_snapshot: dict[str, int] = {} # Snapshot of token balances at proposal time self.has_voted: dict[str, bool] = {} # Track who has voted class GenLayerDAO(IContract): """ Implements the GenLayerDAO contract with bounty management and voting system. Attributes: total_supply (int): Total token supply of the DAO token_supply (int): Current available token supply balances (dict): Mapping of addresses to token balances bounties (dict): Mapping of bounty IDs to Bounty objects next_bounty_id (int): ID to be assigned to the next proposed bounty constitution (list): List of rules governing the DAO """ def __init__(self): self.total_supply = 1000 self.token_supply = self.total_supply self.balances: dict[str, int] = {} self.bounties: dict[int, Bounty] = {} self.next_bounty_id = 1 # Define the constitution of the DAO self.constitution = [ "This Constitution describes the decision-making framework for GenLayerDAO governance.", "The following process governs the rules and procedures by which GenLayerDAO may propose, vote on, and implement Bounty Programs.", "GenLayerDAO's purpose is to grow the GenLayer Blockchain by rewarding Bounty Program contributors with tokens.", "An address must hold at least one token to be a member of the DAO.", "Only members of the GenLayerDAO can propose new Bounty Programs.", "Bounty programs must follow be in line with one of the following goals:", "- Increase Brand Awareness for the GenLayer Blockchain or one of the applications built on top of GenLayer.", "- Lead to Code Contributions to the GenLayer Repository on GitHub.", "- Lead to applications built on top of GenLayer.", "- Empower initiatives that help to build or enhance the community around GenLayer, such as meetups, hackathons, or online forums.", "If a Bounty program proposal does not help any of the listed goals, reject the proposal.", "Bounty programs must be unique. If a new bounty program proposal is the same as an existing proposed or active bounty, reject the proposal." "If a bounty program proposal meets the criteria, it is added to proposed bounties for a vote.", "A bounty program proposal has to be approved by a majority vote.", "The voting power of a member is proportional to the number of tokens a member holds.", "At least one-third of all votable tokens must participate in the voting process; otherwise, the proposal will be rejected", "A majority of those participating votable tokens must agree for the proposal to be accepted", "Once a bounty program is approved, it is moved to the active bounty list", "Anyone can try to claim the reward of an active bounty, according to the rules of the bounty.", "A user does not have to be a member of the DAO or hold any DAO tokens to claim the bounty", ] async def propose_bounty(self, bounty_proposal: str) -> str: """ Proposes a new bounty to the DAO. Args: bounty_proposal (str): Description of the proposed bounty Returns: str: Message indicating the result of the proposal Raises: InsufficientTokensException: If the proposer doesn't have any tokens DAOException: If the proposal is rejected """ proposer = contract_runner.from_address if self.get_balance_of(proposer) == 0: raise InsufficientTokensException("Only DAO members can propose bounties.") # Prepare prompt for LLM evaluation prompt = f""" You are GenLayerDAO. GenLayerDAO has a constitution: {json.dumps(self.constitution)} A user with address "{proposer}" has proposed a new bounty: Description: {bounty_proposal} Evaluate if this bounty proposal adheres to the constitution. Respond with the following JSON format: {{ "reasoning": str, "proposal_accepted": bool }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ result = await call_llm_with_principle(prompt, eq_principle="proposal_accepted has to match exactly.") output = self._get_decode_json_resilient(result) if output["proposal_accepted"]: # Refine the bounty proposal refined_description, refined_reward = await self.refine_bounty_details(bounty_proposal) bounty = Bounty(self.next_bounty_id, refined_description, refined_reward, proposer) bounty.vote_snapshot = self.balances.copy() self.bounties[self.next_bounty_id] = bounty # Automatically cast a vote for the proposer self._cast_vote(bounty, proposer, True) self.next_bounty_id += 1 return f"Bounty proposed successfully and automatically voted for. Bounty ID: {bounty.id}" else: raise DAOException(f"Bounty proposal rejected. Reason: {output['reasoning']}") def vote_on_bounty(self, bounty_id: int, vote: bool) -> str: """ Casts a vote on a proposed bounty. Args: bounty_id (int): ID of the bounty to vote on vote (bool): True for a positive vote, False for a negative vote Returns: str: Message indicating the result of the vote Raises: InvalidBountyException: If the bounty ID is invalid VotingException: If voting conditions are not met """ voter = contract_runner.from_address if bounty_id not in self.bounties: raise InvalidBountyException("Invalid bounty ID.") bounty = self.bounties[bounty_id] if bounty.status != "proposed": raise VotingException("This bounty is not in the voting phase.") if voter not in bounty.vote_snapshot: raise VotingException("You didn't hold any tokens when this bounty was proposed, so you can't vote on it.") if bounty.has_voted.get(voter, False): raise VotingException("You have already voted on this bounty.") self._cast_vote(bounty, voter, vote) return self._check_voting_result(bounty) def _cast_vote(self, bounty: Bounty, voter: str, vote: bool): """ Internal method to cast a vote on a bounty. Args: bounty (Bounty): The bounty being voted on voter (str): Address of the voter vote (bool): True for a positive vote, False for a negative vote """ voter_balance = bounty.vote_snapshot[voter] if vote: bounty.votes_for += voter_balance else: bounty.votes_against += voter_balance bounty.has_voted[voter] = True def _check_voting_result(self, bounty: Bounty) -> str: """ Checks the voting result for a bounty and updates its status if necessary. Args: bounty (Bounty): The bounty to check Returns: str: Message indicating the result of the check """ total_votes = bounty.votes_for + bounty.votes_against if total_votes >= self.total_supply // 3: if bounty.votes_for > bounty.votes_against: bounty.status = "active" return f"Bounty {bounty.id} has been approved and is now active." else: del self.bounties[bounty.id] return f"Bounty {bounty.id} has been rejected and removed." return f"Vote recorded for bounty {bounty.id}." async def refine_bounty_details(self, bounty_proposal: str) -> tuple[str, str]: """ Refines the bounty proposal using an LLM. Args: bounty_proposal (str): Original bounty proposal Returns: tuple: Refined description and reward description """ prompt = f""" You are an LLM helping to refine and standardize bounty proposals for GenLayerDAO. The original bounty proposal is: "{bounty_proposal}" Please improve and structure this proposal by: 1. Separating the description and reward information. 2. Ensuring the description is clear, concise, and specifies concrete deliverables or success criteria. 3. Aligning it with GenLayerDAO's goals (increasing brand awareness, code contributions, application development, or community building). 4. Adding any relevant technical details or requirements. 5. Clarifying and standardizing the reward description, ensuring it's fair and motivating. Provide the refined bounty details in the following JSON format: {{ "refined_description": str, "refined_reward": str }} The refined description should be a single, well-formatted paragraph. The refined reward should be clear and specific, potentially including conditions or tiers if appropriate. It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ result = await call_llm_with_principle(prompt, eq_principle="The refined details should capture the essence of the original proposal.", comparative=False) print(result) output = self._get_decode_json_resilient(result) return output["refined_description"], output["refined_reward"] async def compute_reward(self, bounty_id: int, submission: str) -> int: """ Computes the reward for a bounty submission using an LLM. Args: bounty_id (int): ID of the bounty submission (str): Submitted work for the bounty Returns: int: Computed reward amount Raises: InvalidBountyException: If the bounty ID is invalid """ if bounty_id not in self.bounties: raise InvalidBountyException("Invalid bounty ID") bounty = self.bounties[bounty_id] prompt = f""" You are the GenLayerDAO reward calculator. Your task is to determine the appropriate reward for a bounty submission based on the bounty description, reward description, and the actual submission. Bounty Description: {bounty.description} Reward Description: {bounty.reward_description} Submission: {submission} Please evaluate the submission against the bounty requirements and determine the appropriate reward. Consider factors such as completeness, quality, and impact of the submission. Respond with the following JSON format: {{ "reasoning": str, "reward_amount": int }} The reward_amount should be a whole number of tokens, not exceeding the total supply of {self.total_supply}. It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ result = await call_llm_with_principle(prompt, eq_principle="The proposed reward should match exactly.") output = self._get_decode_json_resilient(result) return min(output["reward_amount"], self.total_supply) # Ensure reward doesn't exceed total supply async def claim_bounty(self, bounty_id: int, submission: str) -> str: """ Processes a claim for a bounty reward. Args: bounty_id (int): ID of the bounty being claimed submission (str): Submitted work for the bounty Returns: str: Message indicating the result of the claim Raises: InvalidBountyException: If the bounty ID is invalid or the bounty is not active InsufficientTokensException: If there are not enough tokens to pay the reward DAOException: If the submission is rejected """ submitter = contract_runner.from_address if bounty_id not in self.bounties: raise InvalidBountyException("Invalid bounty ID.") bounty = self.bounties[bounty_id] if bounty.status != "active": raise InvalidBountyException("This bounty is not active.") if bounty.status == "completed": raise InvalidBountyException("This bounty has already been completed.") prompt = f""" You are GenLayerDAO. A submission has been made for bounty {bounty_id}: Description: {bounty.description} Reward: {bounty.reward_description} Submission: {submission} Evaluate if this submission satisfactorily completes the bounty. Respond with the following JSON format: {{ "reasoning": str, "submission_accepted": bool }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ result = await call_llm_with_principle(prompt, eq_principle="submission_accepted has to match exactly.") output = self._get_decode_json_resilient(result) if output["submission_accepted"]: reward_amount = await self.compute_reward(bounty_id, submission) if self.token_supply < reward_amount: raise InsufficientTokensException(f"Submission accepted, but insufficient tokens to pay reward. Current supply: {self.token_supply}") self._send_tokens(reward_amount, submitter) bounty.status = "completed" bounty.submissions.append({"submitter": submitter, "submission": submission, "accepted": True, "reward": reward_amount}) return f"Bounty {bounty_id} completed. Reward of {reward_amount} tokens sent to {submitter}." else: bounty.submissions.append({"submitter": submitter, "submission": submission, "accepted": False}) raise DAOException(f"Submission for bounty {bounty_id} rejected. Reason: {output['reasoning']}") def buy_tokens(self, amount: int): """ Purchase tokens for the caller. Args: amount (int): The number of tokens to buy. Raises: InvalidInputException: If the amount is not a positive integer. """ if amount <= 0: raise InvalidInputException("Amount must be a positive integer.") self._send_tokens(amount, contract_runner.from_address) def _send_tokens(self, amount: int, holder: str): """ Internal method to send tokens to a holder. Args: amount (int): The number of tokens to send. holder (str): The address of the token recipient. Raises: InvalidInputException: If the amount is not a positive integer. InsufficientTokensException: If there are not enough tokens in the supply. """ if amount <= 0: raise InvalidInputException("Amount must be a positive integer.") if self.token_supply < amount: raise InsufficientTokensException("Insufficient token supply") self.balances[holder] = self.balances.get(holder, 0) + amount self.token_supply -= amount def get_balances(self) -> dict[str, int]: """ Get the token balances of all holders. Returns: dict[str, int]: A dictionary mapping addresses to token balances. """ return self.balances def get_balance_of(self, address: str) -> int: """ Get the token balance of a specific address. Args: address (str): The address to check the balance for. Returns: int: The token balance of the address. """ return self.balances.get(address, 0) def get_bounties(self) -> dict[int, dict]: """ Get all bounties in the system. Returns: dict[int, dict]: A dictionary mapping bounty IDs to bounty details. """ return {id: bounty.__dict__ for id, bounty in self.bounties.items()} def get_bounty(self, bounty_id: int) -> dict: """ Get details of a specific bounty. Args: bounty_id (int): The ID of the bounty to retrieve. Returns: dict: The details of the specified bounty. Raises: InvalidBountyException: If the bounty ID is invalid. """ if bounty_id in self.bounties: return self.bounties[bounty_id].__dict__ raise InvalidBountyException("Invalid bounty ID") def _get_decode_json_resilient(self, s: str) -> dict: """ Decode a JSON string in a resilient manner. Args: s (str): The JSON string to decode. Returns: dict: The decoded JSON object. """ # Clean the string and replace boolean literals clean = self._get_extract_json_from_string(s).replace("True", "true").replace("False", "false") return json.loads(clean) def _get_extract_json_from_string(self, s: str) -> str: """ Extract a JSON object from a string. Args: s (str): The string potentially containing a JSON object. Returns: str: The extracted JSON string, or an empty string if no valid JSON is found. """ start_index = s.find('{') end_index = s.rfind('}') if start_index != -1 and end_index != -1 and start_index < end_index: return s[start_index:end_index + 1] else: return "" ``` # Code Explanation ## Initialization The GenLayerDAO class initializes with a total token supply, empty balances and bounties, and a predefined constitution. ## Key Methods - `propose_bounty()`: Allows members to propose new bounties, evaluated by an AI against the DAO's constitution. - `vote_on_bounty()`: Enables token-weighted voting on proposed bounties. - `claim_bounty()`: Processes bounty submissions and rewards, with AI-assisted evaluation. - Token Management: Methods for buying tokens and checking balances. - Bounty Management: Methods for retrieving bounty information and managing the bounty lifecycle. ## Deploying the Contract To deploy the GenLayerDAO contract: 1. **Deploy the Contract**: No initial parameters are needed. The contract initializes with a predefined token supply and constitution. ## Checking the Contract State After deploying the contract, you can check its state in the Read Methods section: - Use `get_balances()` to view token distributions among members. - Use `get_bounties()` to see all current bounties and their statuses. - Use `get_bounty(bounty_id)` to view details of a specific bounty. ## Executing Transactions To interact with the deployed contract, go to the Write Methods section. Here, you can: - Call `propose_bounty(bounty_proposal)` to suggest a new bounty. - Call `vote_on_bounty(bounty_id, vote)` to cast a vote on a proposed bounty. - Call `claim_bounty(bounty_id, submission)` to submit work for an active bounty. - Call `buy_tokens(amount)` to acquire governance tokens. ## Analyzing the Contract's Behavior The contract's behavior involves several complex processes: 1. AI-Assisted Proposal Evaluation: Uses an LLM to evaluate bounty proposals against the DAO's constitution. 2. Token-Weighted Voting: Implements a voting system where voting power is proportional to token holdings. 3. Dynamic Reward Calculation: Employs an AI to determine appropriate rewards for bounty submissions. 4. Automated Governance: Manages the entire lifecycle of bounties from proposal to completion. ## Handling Different Scenarios - **Bounty Proposal**: A member proposes a bounty, which is evaluated by AI. If accepted, it moves to the voting phase. - **Voting Process**: Members vote on proposed bounties, with decisions based on token-weighted majority and quorum requirements. - **Bounty Activation**: Approved bounties become active and open for submissions. - **Bounty Claim**: Submissions are evaluated by AI, and if accepted, rewards are automatically distributed. ## Use Cases and Benefits The GenLayerDAO contract is ideal for: - Decentralized Decision Making: Communities seeking fair and transparent governance. - Ecosystem Growth: Blockchain projects incentivizing development and community engagement. - Open Source Development: Managing and rewarding contributions to open-source projects. Benefits include: - Flexibility: AI-powered system can interpret and execute a wide range of proposals. - Scalability: Can handle growing membership and increasing complexity of decisions. - Transparency: All decisions and their reasoning are recorded on the blockchain. ## Future Enhancements Potential future developments could include: 1. Multi-tiered Governance: Implementing different levels of decision-making authority. 2. Integration with External Systems: Connecting with GitHub or other platforms for seamless contribution tracking. 3. Advanced Analytics: Implementing tools to analyze voting patterns and DAO performance over time. This GenLayerDAO contract demonstrates a sophisticated use of blockchain technology, combining token economics, AI-assisted decision-making, and community governance. It showcases how smart contracts can create complex, self-governing systems that incentivize participation and manage resources in a decentralized manner. # developers/intelligent-contracts/examples/git-bounties.mdx import { Callout } from 'nextra-theme-docs' # GitBounties Contract The GitBounties contract sets up a scenario to manage bounties for GitHub issues, allowing developers to claim points for resolving issues. This contract demonstrates more complex interactions involving external data (GitHub) and multi-step processes within a blockchain environment. This intelligent contract is currently not migrated to the real GenVM syntaxis. ```python import json import math from backend.node.genvm.icontract import IContract from backend.node.genvm.equivalence_principle import ( EquivalencePrinciple, get_webpage_with_principle, ) class BountyData: issue: int points: int claimed: bool def __init__(self, issue, points): self.issue = issue self.points = points self.claimed = False class GitBounties(IContract): def __init__(self, github_repository: str): self.owner = contract_runner.from_address self.repository = "https://github.com/" + github_repository self.developers = {} # Mapping from: GitHub username -> Address self.points = {} # Mapping from: GitHub username -> points earned self.bounties = {} # Mapping from: Issue number -> BountyData pass def get_developers(self) -> dict: return self.developers def get_points(self) -> dict: return self.points def get_bounties(self) -> dict: bounties = {} for k, v in self.bounties.items(): bounties[k] = {"issue": v.issue, "points": v.points, "claimed": v.claimed} return bounties def add_bounty(self, issue: int, points: int): if self.owner != contract_runner.from_address: raise Exception("only owner") bounty = self.bounties.setdefault(issue, BountyData(issue, points)) if bounty.claimed: raise Exception("can't add bounty to claimed issue") async def register(self, github_username: str) -> None: dev_github_profile = f"https://github.com/{github_username}" developer_address = contract_runner.from_address web_data = await get_webpage_with_principle( dev_github_profile, "The result should be exactly the same" ) if developer_address in web_data["output"]: self.developers[github_username] = developer_address else: raise Exception( "Couldn't verify the developer, GitHub profile page must have the given address on its bio" ) async def claim(self, pull: int) -> None: final_result = {} async with EquivalencePrinciple( result=final_result, principle="The result should be exactly the same", comparative=True, ) as eq: web_data = await eq.get_webpage(self.repository + "/pull/" + str(pull)) task = f""" The following web page content corresponds to a GitHub pull request. Web page content: {web_data} End of web page data. In that Pull Request, a developer should be fixing an issue from the repository issues list: located at: https://github.com/cristiam86/genlayer-hackaton/issues To fin the issue, you should look for a text like "Fixes: #" in the Pull Request first comment. It is very important to also include information about how many times a given PR has ben rejected (changes requested), son include the number of those as well. Respond with the following JSON format: {{ "merged": boolean, // if pull request was merged "username": string, // GitHub username of the developer who opened a pull request "issue": int, // number of the closed issue "changes_requested": int // number of changes requested for the given pull request }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ result = await eq.call_llm(task) print("\nresult: ", result) eq.set(result) res = json.loads(final_result["output"]) if not res["merged"]: raise Exception("pull is not mergerd") bounty_issue = res["issue"] bounty_username = res["username"] pull_request_changes_requested = res["changes_requested"] bounty = self.bounties.get(bounty_issue, None) if bounty and not bounty.claimed: bounty.claimed = True if not bounty_username in self.points: self.points[bounty_username] = 0 total_points = math.floor( bounty.points / (pull_request_changes_requested + 1) ) print("total_points", total_points) self.points[bounty_username] += 1 if total_points <= 1 else total_points ``` ## Code Explanation - **Initialization**: The `GitBounties` class initializes the contract with a GitHub repository, setting up data structures for developers, points, and bounties. - **Read Methods**: - `get_developers()`: Returns the mapping of GitHub usernames to blockchain addresses. - `get_points()`: Returns the mapping of GitHub usernames to earned points. - `get_bounties()`: Returns the current bounties and their status. - **Write Methods**: - `add_bounty(issue, points)`: Allows the owner to add a new bounty for an issue. - `register(github_username)`: Allows developers to register by linking their GitHub profile to their blockchain address. - `claim(pull)`: Processes a claim for a resolved issue, awarding points based on the bounty and the number of change requests asked by reviewers. ## Deploying the Contract To deploy the GitBounties contract, you need to provide the GitHub repository: 1. **Set GitHub Repository**: Provide the GitHub repository in the format "username/repository". 2. **Deploy the Contract**: Once the repository is set, deploy the contract to make it ready for interaction. ## Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. - Use `get_developers()` to see registered developers. - Use `get_points()` to see points earned by developers. - Use `get_bounties()` to see all current bounties and their status. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can: - Call `add_bounty(issue, points)` to create a new bounty (owner only). - Call `register(github_username)` for developers to register. - Call `claim(pull)` to process a claim for a resolved issue. ## Analyzing the Contract's Behavior The contract's behavior involves several complex interactions: - **Adding Bounties**: Only the contract owner can add bounties for specific issues. - **Developer Registration**: Developers must register by providing their GitHub username. The contract verifies that their address has been added to their GitHub profile. - **Claiming Bounties**: When a developer claims a bounty: - The contract fetches the pull request data from GitHub. - It verifies if the pull request is merged and identifies the associated issue. - It calculates points based on the bounty value and the number of change requests. - Points are awarded to the developer who resolved the issue. ## Handling Different Scenarios - **Successful Claim**: When a valid claim is processed, the bounty is marked as claimed, and points are awarded to the developer. - **Invalid Claim**: If the pull request is not merged or doesn't reference a valid bounty, the claim is rejected. - **Point Calculation**: The number of change requests affects the points awarded, with more changes resulting in fewer points. - **Minimum Points**: A minimum of 1 point is always awarded for a successful claim. This GitBounties contract demonstrates a complex use case involving external data integration, multi-step verification processes, and dynamic point calculation. It showcases how blockchain contracts can interact with real-world systems to create incentive structures for open-source contributions. # developers/intelligent-contracts/examples/influencer-tweet-analyzer.mdx import { Callout } from 'nextra-theme-docs' # Influencer Tweet Analyzer Contract The Influencer Tweet Analyzer contract sets up a system for analyzing cryptocurrency-related tweets from influencers, evaluating their impact on market prices, and managing a leaderboard of influencers based on their predictive accuracy. This contract demonstrates complex social media analysis, market data integration, and automated investment simulation within a blockchain environment. This intelligent contract is currently not migrated to the real GenVM syntaxis. ```python from typing import List from backend.node.genvm.icontract import IContract from backend.node.genvm.equivalence_principle import EquivalencePrinciple import json # TODO: handle duplication of tweet feeds class InfluencerTweetAnalyzer(IContract): # AnalyzedTweet is defined here due to problems "compiling" the contract in the Studio from dataclasses import dataclass @dataclass class AnalyzedTweet: influencer: str tweet: str date: str cryptocurrency: str positive_sentiment: float def __init__(self) -> None: from collections import defaultdict self.leaderboard: dict[str, float] = {} # influencer -> score self.price_history: dict[str, dict[str, float]] = defaultdict( dict ) # cryptocurrency -> date -> price self.tweets_pending_process: List[InfluencerTweetAnalyzer.AnalyzedTweet] = [] self.balances: dict[str, int] = defaultdict(int) # address -> balance self.followers: dict[str, set[str]] = defaultdict( set ) # influencer -> followers addresses self.followers_investments: dict[str, int] = defaultdict( self._default_int_dict ) # address -> cryptocurrency -> investment. Simulates interactions with other coins def _default_int_dict( self, ): # This is a workaround for the fact that lambdas don't work in the Studio from collections import defaultdict return defaultdict(int) async def feed(self, influencer: str, tweet: str, date: str): """ Inputs: - influencer: the name of the influencer - tweet: the tweet content - date: the date of the tweet Process: 1. Analyze the tweet to determine if sentiment is positive towards one or more cryptocurrencies - This step uses Consensus to analyze the tweet - We save these results in a list of tweets pending process, one per cryptocurrency """ if influencer not in self.leaderboard: # influencer enters the leaderboard self.leaderboard[influencer] = 0 tweet_result = {} async with EquivalencePrinciple( result=tweet_result, principle="The cryptocurrencies names are the exact same, and the positive_senitment is similar", comparative=True, ) as eq: # TODO: actually retrieve from the internet # web_data = await eq.get_webpage(tweet) # print(web_data) web_data = tweet task = f"""In this webpage you'll find a tweet from a crypto influencer. Analyze this tweet to determine if sentiment is positive towards one or more cryptocurrencies Return the output as a JSON array of cryptocurrencies and their positive sentiment. - 'positive_sentiment' should go from -1 to 1. - 'cryptocurrency' should be the entire name of the cryptocurrency, all in lowercase, only letters Here's an example format: [ {{ "cryptocurrency": "bitcoin", "positive_sentiment": 0.1 }} ] Respong ONLY with the JSON output, nothing else. The output should be parsable by any JSON parser Web page content: {web_data} """ result = await eq.call_llm(task) print(result) eq.set(result) tweet_result = json.loads(tweet_result["output"]) for item in tweet_result: analyzed_tweet = InfluencerTweetAnalyzer.AnalyzedTweet( influencer=influencer, tweet=tweet, date=date, cryptocurrency=item["cryptocurrency"], positive_sentiment=item["positive_sentiment"], ) self.tweets_pending_process.append(analyzed_tweet) if date == self._today(): self._update_follower_investments(analyzed_tweet) def _today(self) -> str: from datetime import date return date.today().strftime("%Y-%m-%d") def _update_follower_investments(self, analyzed_tweet: AnalyzedTweet): # TODO: can we make this contract interact with other Ethereum contracts like ERC20? # TODO: sentiment threshold and investment amount are arbitrary if analyzed_tweet.positive_sentiment > 0.5: # Buy for follower in self.followers[analyzed_tweet.influencer]: if self.balances[follower] > 0: self.balances[follower] -= 1 self.followers_investments[follower][ analyzed_tweet.cryptocurrency ] += 1 elif analyzed_tweet.positive_sentiment < -0.5: # Sell for follower in self.followers[analyzed_tweet.influencer]: if self.followers_investments[follower] > 0: self.balances[follower] += 1 self.followers_investments[follower][ analyzed_tweet.cryptocurrency ] -= 1 async def process_score(self): """ 1. For each analyzed tweet, get the daily price change of the cryptocurrency - This step uses Consensus and connects to the Internet to get the price change 2. Update the leaderboard with the score of the influencer, based on alignment between sentiment and price change """ tweets_pending_process_from_today = [] for tweet in self.tweets_pending_process: if tweet.date == self._today(): # We skip today's tweets since there's no market data yet tweets_pending_process_from_today.append(tweet) continue price_change = await self.retrieve_market_data( tweet.cryptocurrency, tweet.date ) # This is a simple score function for demonstration self.leaderboard[tweet.influencer] += ( price_change * tweet.positive_sentiment ) self.tweets_pending_process = tweets_pending_process_from_today # TODO: use date async def retrieve_market_data(self, cryptocurrency: str, date: str) -> float: if cryptocurrency in self.price_history: if date in self.price_history[cryptocurrency]: return self.price_history[cryptocurrency][date] market_result = {} async with EquivalencePrinciple( result=market_result, principle="The price ", comparative=True, ) as eq: url = "https://coinmarketcap.com/currencies/" + cryptocurrency web_data = await eq.get_webpage(url) print(web_data) task = f"""In this webpage from 'coinmarketcap' you'll find a lot of information about the market status of a cryptocurrency. Analyze this information to determine today's daily price change of the cryptocurrency. Return the output as a JSON number bigger than -100, representing the daily price change. - Negative numbers mean that the price went down - Positive numbers mean that the price went up Respong ONLY with the JSON output, nothing else, not even the word "json". The output should be parsable by any JSON parser Example output: {{ "price_change": 2.4 }} Web page content: {web_data} """ result = await eq.call_llm(task) print(result) eq.set(result) market_data = json.loads(market_result["output"])["price_change"] self.price_history[cryptocurrency][date] = market_data return market_data def deposit(self, amount: int): self.balances[contract_runner.from_address] += amount def follow(self, influencer: str): self.followers[influencer].add(contract_runner.from_address) def unfollow(self, influencer: str): self.followers[influencer].remove(contract_runner.from_address) # Read methods def get_leaderboard(self): return self.leaderboard def get_price_history(self): return self.price_history def get_tweets_pending_process(self): return [item.__dict__ for item in self.tweets_pending_process] def get_followers_investments(self): return self.followers_investments def get_followers(self): return {key: list(value) for key, value in self.followers.items()} def get_all_state(self): # We convert them so they are json serializable return { "leaderboard": self.leaderboard, "price_history": self.price_history, "tweets_pending_process": self.get_tweets_pending_process(), "balances": self.balances, "followers": self.get_followers(), "followers_investments": self.followers_investments, } async def test(self): influencer = "Chris Burniske" self.deposit(1000) self.follow(influencer) # New tweet, should create movement in followers investments await self.feed( influencer=influencer, tweet=""" Each cycle I've tended to give a majority of focus to one major underdog. In 2014-17 that was $BTC, in 2018-2021 that was $ETH, and in 2022 to now that's $SOL. """, date=self._today(), ) other_influencer = "Wizard Of SoHo" self.follow(other_influencer) # Old tweet, should be processed for leaderboard score await self.feed( influencer=other_influencer, tweet=""" @Nate_Rivers @osf_rekt I don't think so. Doge had Elon like max shilling. No other memecoin has made it otherwise. Who is gonna drive pepe up again? No coin makes it without some leaders pushing it or large holders. Here the large holders are jeet scam devs with no rep outside of shitcoin world """, date="2024-08-16", ) await self.process_score() ``` ## Code Explanation - **Initialization**: The `InfluencerTweetAnalyzer` class initializes with empty data structures for the leaderboard, price history, pending tweets, user balances, and follower relationships. - **Key Methods**: - `feed()`: Analyzes a tweet to determine sentiment towards cryptocurrencies using an LLM. - `process_score()`: Updates the leaderboard based on the alignment between tweet sentiment and actual price changes. - `retrieve_market_data()`: Fetches and processes cryptocurrency price data from an external source. - **User Interaction Methods**: - `deposit()`: Allows users to deposit funds into their account. - `follow()` and `unfollow()`: Enables users to follow or unfollow influencers. - **Read Methods**: Various getter methods to retrieve contract state, leaderboard, price history, and user data. ## Deploying the Contract To deploy the Influencer Tweet Analyzer contract: 1. **Deploy the Contract**: No initial parameters are needed. ## Checking the Contract State After deploying the contract, you can check its state using the Read Methods: - Use `get_leaderboard()` to view the current influencer rankings. - Use `get_price_history()` to see historical cryptocurrency prices. - Use `get_followers()` to check follower relationships. - Use `get_all_state()` to retrieve the entire contract state. ## Executing Transactions To interact with the deployed contract, use the Write Methods: - Call `feed(influencer, tweet, date)` to input new tweets for analysis. - Call `process_score()` to update the leaderboard based on recent market data. - Call `deposit(amount)` to add funds to a user's account. - Call `follow(influencer)` or `unfollow(influencer)` to manage influencer subscriptions. ## Analyzing the Contract's Behavior The contract's behavior involves several complex processes: 1. **Sentiment Analysis**: Uses an LLM to analyze tweets and determine sentiment towards specific cryptocurrencies. 2. **Market Data Integration**: Fetches and processes real-time cryptocurrency price data. 3. **Automated Scoring**: Updates the influencer leaderboard based on the accuracy of their implied predictions. 4. **Simulated Investments**: Automatically adjusts follower investments based on influencer tweets. ## Handling Different Scenarios - **New Tweet Analysis**: When a new tweet is fed, it's analyzed for sentiment and potentially triggers simulated investments for followers. - **Historical Tweet Processing**: Older tweets are used to update the leaderboard based on actual market performance. - **User Following/Unfollowing**: Users can dynamically change their subscriptions, affecting their simulated investment behavior. ## Use Cases and Market Potential The Influencer Tweet Analyzer contract has several potential applications: - **Crypto Investment Guidance**: Provides users with insights based on influencer performance. - **Influencer Accountability**: Creates a transparent system for tracking the accuracy of cryptocurrency predictions. - **Automated Trading Strategies**: Could be extended to implement real trading based on influencer sentiment. - **Market Sentiment Analysis**: Offers a tool for understanding the relationship between social media sentiment and market movements. ## Future Enhancements Potential future developments include: 1. **Real-time Tweet Fetching**: Implementing an external service to automatically fetch tweets from followed influencers. 2. **Advanced Sentiment Analysis**: Refining the LLM prompts for more nuanced sentiment evaluation. 3. **Integration with Trading Platforms**: Connecting with real cryptocurrency exchanges for actual trading based on the contract's analysis. 4. **User Customization**: Allowing users to set their own risk preferences and investment thresholds. 5. **Expanded Market Data**: Incorporating more comprehensive and real-time market data sources. This Influencer Tweet Analyzer contract demonstrates an innovative use of GenLayer for social media analysis and cryptocurrency market prediction. It showcases how Intelligent Contracts can process complex, real-world data streams, provide valuable insights, and potentially guide investment decisions in a decentralized and transparent manner. # developers/intelligent-contracts/examples/llm-token.mdx import Image from 'next/image' import { Callout } from 'nextra-theme-docs' # LLM Token Contract Documentation The LLM Token Contract sets up a scenario to manage token transactions between users, ensuring that each transaction is valid and updating balances accordingly. The contract uses the Equivalence Principle to maintain consistency and accuracy. ```python # { "Depends": "py-genlayer:test" } import json from genlayer import * @gl.contract class LlmErc20: balances: TreeMap[Address, u256] def __init__(self, total_supply: int) -> None: self.balances[gl.message.sender_account] = u256(total_supply) @gl.public.write def transfer(self, amount: int, to_address: str) -> None: prompt = f""" You keep track of transactions between users and their balance in coins. The current balance for all users in JSON format is: {json.dumps(self.get_balances())} The transaction to compute is: {{ sender: "{gl.message.sender_account.as_hex}", recipient: "{Address(to_address).as_hex}", amount: {amount}, }} For every transaction, validate that the user sending the Coins has enough balance. If any transaction is invalid, it shouldn't be processed. Update the balances based on the valid transactions only. Given the current balance in JSON format and the transaction provided, please provide the result of your calculation with the following format: {{ "transaction_success": bool, // Whether the transaction was successful "transaction_error": str, // Empty if transaction is successful "updated_balances": object // Updated balances after the transaction }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parsable by a JSON parser without errors.""" print(prompt) def run(): res = gl.exec_prompt(prompt) res = res.replace("```json", "").replace("```", "") return res final_result = gl.eq_principle_prompt_comparative( run, """The new_balance of the sender should have decreased in the amount sent and the new_balance of the receiver should have increased by the amount sent. Also, the total sum of all balances should have remain the same before and after the transaction""", ) print("final_result: ", final_result) result_json = json.loads(final_result) for k, v in result_json["updated_balances"].items(): self.balances[Address(k)] = v @gl.public.view def get_balances(self) -> dict[str, int]: return {k.as_hex: v for k, v in self.balances.items()} @gl.public.view def get_balance_of(self, address: str) -> int: return self.balances.get(Address(address), 0) ``` ### Code Explanation - **Initialization**: The `LlmErc20` class initializes the contract with a total supply of tokens assigned to the contract creator's address. `[contract_runner["from_address"]]` represents the address that called the contract function, helping to track and validate transactions. - **Prompts**: Next, we construct prompts to ensure that the LLM can accurately validate and process transactions based on the provided user balances and transaction details (sender, recipient, and amount). This prompt is sent to the language model (LLM) for processing and validation. - **EquivalencePrinciple**: The Equivalence Principle validates that the sender's balance decreases by the amount sent, the recipient's balance increases by the same amount, and the total sum of all balances remains unchanged. - **JSON Response**: The LLM processes the prompt and returns a JSON response indicating the transaction status and updated balances. - **Balance Update**: The contract updates the balances based on the LLM response. - **Balance Retrieval Methods**: - `get_balances()`: Returns the balances of all users. - `get_balance_of(address)`: Returns the balance of a specific user given their address. You can view this code on our [GitHub](https://github.com/yeagerai/genlayer-simulator/blob/main/examples/contracts/llm_erc20.py). ## Deploying the Contract To deploy the ERC-20 Token contract, you need to initialize the contract state correctly. This setup will determine how the contract manages token transactions. 1. **Set Total Supply**: Provide the total supply of tokens. The `total_supply` constructor parameter is detected from the code. For example, you might set `total_supply` to 1000. 2. **Deploy the Contract**: Once the total supply is set, deploy the contract to make it ready to interact and process token transactions. ### Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. Use the `get_balances()` function to see the balances of all users and the `get_balance_of(address)` function to see the balance of a specific user. ### Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `transfer` method to process a token transfer. This triggers the contract's logic to validate the transaction and update balances based on the Equivalence Principle criteria defined. Execute Transactions ### Analyzing the Contract's Decisions When the `transfer` method is executed: - The LLM processes the transaction details. - It validates the transaction according to the Equivalence Principle defined in the code. - It returns a JSON response that includes the transaction status and updated balances. ### Handling Different Scenarios - **Valid Transactions**: If the sender has enough balance, the transaction is successful. The sender's balance decreases by the amount sent, and the recipient's balance increases by the same amount. The total sum of all balances remains unchanged. - **Invalid Transactions**: If the sender does not have enough balance, the transaction fails. The balances remain unchanged, and the JSON response includes an error message. You can view the logs to see detailed information about the contract interaction. --- # developers/intelligent-contracts/examples/prediction.mdx # Prediction Market Contract The Prediction Market contract sets up a scenario to determine the outcome of a football game between two teams. The contract uses the Equivalence Principle to ensure accurate and consistent decision-making based on the game's resolution data. ```python filename="PredictionMarket" copy # { "Depends": "py-genlayer:test" } from genlayer import * import json import typing @gl.contract class PredictionMarket: has_resolved: bool game_date: str team1: str team2: str resolution_url: str def __init__(self, game_date: str, team1: str, team2: str): """ Initializes a new instance of the prediction market with the specified game date and teams. Args: game_date (str): The date of the game in the format 'YYYY-MM-DD'. team1 (str): The name of the first team. team2 (str): The name of the second team. Attributes: has_resolved (bool): Indicates whether the game's resolution has been processed. Default is False. game_date (str): The date of the game. resolution_url (str): The URL to the game's resolution on BBC Sport. team1 (str): The name of the first team. team2 (str): The name of the second team. """ self.has_resolved = False self.game_date = game_date self.resolution_url = ( "https://www.bbc.com/sport/football/scores-fixtures/" + game_date ) self.team1 = team1 self.team2 = team2 @gl.public.write def resolve(self) -> typing.Any: if self.has_resolved: return "Already resolved" def nondet() -> str: web_data = gl.get_webpage(self.resolution_url, mode="text") print(web_data) task = f"""In the following web page, find the winning team in a matchup between the following teams: Team 1: {self.team1} Team 2: {self.team2} Web page content: {web_data} End of web page data. If it says "Kick off [time]" between the names of the two teams, it means the game hasn't started yet. If you fail to extract the score, assume the game is not resolved yet. Respond with the following JSON format: {{ "score": str, // The score with numbers only, e.g, "1:2", or "-" if the game is not resolved yet "winner": int, // The number of the winning team, 0 for draw, or -1 if the game is not yet finished }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parsable by a JSON parser without errors. """ result = gl.exec_prompt(task).replace("```json", "").replace("```", "") print(result) return json.dumps(json.loads(result), sort_keys=True) result_json = json.loads(gl.eq_principle_strict_eq(nondet)) if result_json["winner"] > -1: self.has_resolved = True self.winner = result_json["winner"] self.score = result_json["score"] return result_json ``` You can check out this code on our [GitHub](https://github.com/yeagerai/genlayer-simulator/blob/main/examples/contracts/football_prediction_market.py) ## Deploying the Contract To deploy the Prediction Market contract, you'll need to initialize the contract state correctly. This will impact how the contract will respond to the game's resolution. 1. Provide the game date and the names of the two teams. The `game_date`, `team1`, and `team2` constructor parameters are automatically detected from the code. For example, you might set `game_date` to "2024-06-05", `team1` to "Brazil", and `team2` to "Jamaica". 2. Once the game details are set, deploy the contract to make it ready to interact and resolve the game results. import Image from 'next/image' ## Checking the Contract State Once the contract is deployed, its address is displayed as well as the **Read Methods** section. In this case, there are no Read Methods defined. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `resolve` method to process the game's result. This triggers the contract's logic to retrieve the game's data and determine the outcome based on the Equivalence Principle criteria defined. Execute Transactions ## Analyzing the Contract's Decisions When the `resolve` method is executed: - The LLM retrieves the game data from the specified URL. - It validates the game's outcome according to the Equivalence Principle defined in the code. - Finally, it returns a JSON response that includes the game's score and the winner. ### Handling Different Scenarios - If the game has started but not finished, the JSON response will indicate the game is not resolved yet. - If the game has finished, the JSON response will include the final score and the winning team. - If the game hasn't started, the JSON response will indicate this status. You can view the logs to see detailed information about the contract interaction. # developers/intelligent-contracts/examples/purellm-dao.mdx import { Callout } from 'nextra-theme-docs' # PureLLM DAO Contract The PureLLM DAO contract implements a simplified, AI-driven Decentralized Autonomous Organization (DAO) that relies entirely on language model decision-making. This contract demonstrates extreme flexibility in governance by interpreting and executing natural language proposals within a blockchain environment. This intelligent contract is currently not migrated to the real GenVM syntaxis. ```python import json from backend.node.genvm.icontract import IContract from backend.node.genvm.equivalence_principle import call_llm_with_principle class ConstitutionalDAO(IContract): """ A Constitutional DAO that uses AI to interpret and execute motions. This DAO maintains a state and can update it based on user-submitted motions. """ def __init__(self): """ Initialize the ConstitutionalDAO with a basic constitution. """ self.state = json.dumps({ "constitution": [ "1. Anyone can become a member of the DAO", "2. The constitution of the DAO can be updated by a unanimous vote" ] }) async def execute_motion(self, motion: str) -> None: """ Execute a motion proposed by a user. This method interprets the motion using an AI model and updates the DAO state accordingly. Args: motion (str): The motion proposed by a user. Returns: None """ # Prepare the prompt for the language model prompt = f""" You are a constitutional DAO Your state is as follows: {self.state} User with the address "{contract_runner.from_address}" has made the following motion: {motion} Decide how to proceed Respond with the following JSON format: {{ "reasoning": str, // Your reasoning "updated_state": any, // The new state of the DAO - can be any format }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ # Call the language model with the equivalence principle result = await call_llm_with_principle( prompt, eq_principle="The updated state has to be essentially equivalent", ) # Clean up the result and parse it as JSON result_clean = result.replace("True", "true").replace("False", "false") output = json.loads(result_clean) # Update the DAO state self.state = json.dumps(output["updated_state"]) def get_state(self) -> str: """ Get the current state of the DAO. Returns: str: The current state of the DAO as a JSON string. """ return self.state ``` ## Code Explanation - **Initialization**: The ConstitutionalDAO class initializes with a basic constitution stored as a JSON string in the state variable. - **Key Methods**: - `execute_motion(motion)`: Processes a text-based motion submitted by any user. It uses an AI model to interpret the motion and update the DAO's state accordingly. - **State Management**: - `get_state()`: Allows retrieval of the current DAO state. ## Deploying the Contract To deploy the ConstitutionalDAO contract: 1. Deploy the Contract: No initial parameters are needed. The contract initializes with a basic constitution. ## Checking the Contract State After deploying the contract, you can check its state in the Read Methods section. - Use `get_state()` to view the current state of the DAO, including its constitution and any other properties that have been added through motions. ## Executing Transactions To interact with the deployed contract, go to the Write Methods section. Here, you can: - Call `execute_motion(motion)` to propose and execute a change to the DAO. This is the primary method of interaction with the contract. ## Analyzing the Contract's Behavior The contract's behavior involves a single, highly flexible process: ### AI-Driven Motion Execution: 1. A user submits a motion in natural language. 2. The AI interprets the motion in the context of the current DAO state. 3. The AI decides how to update the state based on its interpretation. 4. The contract's state is updated according to the AI's decision. ## Handling Different Scenarios The ConstitutionalDAO can handle a wide range of scenarios through its flexible motion execution: - Constitutional Amendments: Users can propose changes to the DAO's constitution. - New Feature Proposals: Motions can suggest adding new functionalities to the DAO. - Resource Allocation: Users might propose ways to manage or distribute resources. - Membership Rules: Motions could alter how membership in the DAO is determined or managed. - Decision-Making Processes: The very process of how decisions are made could be altered through motions. ## Use Cases and Benefits The ConstitutionalDAO contract is ideal for: - Experimental Governance: Organizations looking to explore highly adaptive governance models. - Rapid Iteration: Communities that need to quickly evolve their structure and rules. - Complex Decision-Making: Scenarios where decisions require nuanced interpretation and execution. Benefits include: - Extreme Flexibility: Can handle a wide range of governance actions without predefined structures. - Natural Language Interface: Allows users to interact with the DAO using everyday language. - Adaptive Governance: The DAO can evolve its own rules and structure over time based on member input. ## Limitations and Considerations While powerful, this approach has some important considerations: 1. AI Dependence: The reliability and effectiveness of the DAO are heavily dependent on the capabilities of the AI model. 2. Interpretation Accuracy: There's a risk of misinterpretation of motions, which could lead to unintended outcomes. 3. Language Precision: Users need to be careful in how they word their motions to ensure accurate interpretation. 4. Lack of Traditional Checks and Balances: The flexibility could potentially lead to rapid, drastic changes without traditional safeguards. ## Future Enhancements Potential improvements to this system could include: 1. Multi-Step Approval Process: Implementing a confirmation step before major changes are executed. 2. Historical Tracking: Maintaining a log of all executed motions and their impacts on the DAO state. 3. User Reputation System: Incorporating a system that weighs motions based on the proposer's past contributions or reputation. This ConstitutionalDAO contract demonstrates an innovative and highly flexible approach to decentralized governance. It showcases how advanced AI can be integrated with blockchain technology to create adaptive, language-driven organizational structures. While powerful, it also highlights the challenges and considerations in creating AI-driven governance systems. # developers/intelligent-contracts/examples/rokos-mansion.mdx import { Callout } from 'nextra-theme-docs' # RokosMansion Contract The RokosMansion contract sets up a scenario for an interactive text-based game where players explore Professor Roko's mansion, solve puzzles, and interact with the environment to prevent a malicious artificial superintelligence (ASI) from taking control. This contract demonstrates complex game logic, dynamic content generation, and player interactions within a blockchain environment. This intelligent contract is currently not migrated to the real GenVM syntaxis. ```python """ Module: RokosMansion Description: Implements the RokosMansion game contract. """ import json from backend.node.genvm.icontract import IContract from backend.node.genvm.equivalence_principle import call_llm_with_principle class RokosMansion(IContract): """ RokosMansion game contract class. This class represents the game logic for the Mansion of Professor Roko game. It handles the game state, page transitions, and interactions with the game environment. Attributes: _allowed_styles (list): List of allowed writing styles. _style (str): Selected writing style. _allowed_countries (list): List of allowed country styles. _country (str): Selected country style. _inventory (list): Player's inventory. _environment (str): String summarizing the changes in the environment. _current_page_number (int): Current page number. _current_page (str): Current page content. page_text_gen (dict): Generated page text. page_actions_gen (dict): Generated page actions. page_text (dict): Default page text. page_actions (dict): Default page actions. """ def __init__(self, style: str = "Stephen King", country: str = "USA"): """ Initialize the RokosMansion contract. Args: style (str): Writing style. Defaults to "Stephen King". country (str): Country style. Defaults to "USA". Raises: AssertionError: If the provided style, country is not allowed. """ self._allowed_styles = ["Stephen King", "HP Lovecraft", "Clive Barker", "Yukio Mishima"] assert style in self._allowed_styles self._style = style self._allowed_countries = ['Andorra', 'Argentina', 'Brazil', 'España', 'Latvia', 'Portugal', 'Russia', 'Thailand', 'USA', 'Venezuela','Japan'] assert country in self._allowed_countries self._country = country self._inventory = [] # list of strings self._environment = "" self._current_page_number = 5 self._current_page = "" self.page_text_gen = {} self.page_actions_gen = {} self.puzzles_solved = [] self.puzzles_for_victory = 3 self.victory_page = 11 self.page_puzzles = {} self.page_puzzles[3] = "Each box is labeled, but all labels are incorrect. One box contains only **Poison**, one contains only **Antidote**, and the last contains **Both Poison and Antidote**. The puzzle asks you to pick one item from any box, knowing that the labels are wrong. For example, if you pick from the box labeled 'Both Poison and Antidote,' whatever you pull will reveal how to correctly label all three boxes. Solving this puzzle deactivates the ASI’s device in the library and allows you to proceed.", self.page_puzzles[4] = "The room’s puzzle involves analyzing the behavior of Organics and Synthetics, two types of beings affected by the ASI: Organics believe everything while awake is true, and everything while asleep is false, while Synthetics believe the opposite. The puzzle asks you to determine the truth of the statement: 'Any person that is awake believes they are organic.' Solve it to deactivate the ASI’s device in the room." self.page_puzzles[5] = "Guard 1 (a guard who lies only when talking about uranium) says 'The materials are either uranium or thorium,' Guard 2 (a guard who lies when talking about plutonium) says 'The secret material is plutonium'; solve their statements to determine the correct radioactive material and sever the ASI's timeline connection." self.page_puzzles_action = {} self.page_puzzles_action[3] = " To solve this puzzle you must choose ONLY one box and be logically consistent with the conditions.", self.page_puzzles_action[4] = " To solve this puzzle you must clearly say if the statement is true or false, and be logically consistent with the puzzle conditions." self.page_puzzles_action[5] = "To solve this puzzle you must clearly say if the secret material mentioned by the Guards is plutonium, uranium or thorium, and be logically consistent with that what the Guards have said." self.page_text = { 1: "Arrival at the Mansion: You are an engineer named Alex, invited to visit the mansion of Professor Roko, a notorious mad scientist known for dabbling in AI technology. Upon arrival, the mansion seems eerie, its large doors creaking open on their own. As you step inside, you feel a strange presence. A hologram of Professor Roko appears and reveals that he has made contact with a malicious artificial superintelligence (ASI) from the future. The ASI is sending cryptic messages and puzzles through devices scattered across the mansion.", 2: "The Entrance Hall: You stand in the grand entrance hall of the mansion with several doors leading to different rooms. Roko's hologram reappears, urging you to hurry, as the ASI grows stronger by the minute. Your task is to solve three logical puzzles hidden within the mansion to weaken the ASI's influence. However, you can explore the rooms to gather information and insights.", 3: "The Library: The library is a vast room filled with towering bookshelves and strange devices. In the center, an ancient machine hums softly, connected to three mysterious boxes.", 4: "The Study: The study is a small room filled with strange devices, a desk cluttered with blueprints and journals, and a glowing cube resting on the desk.", 5: "The Laboratory: A futuristic room where two robotic guards protect a vault containing either uranium, plutonium, or thorium .", 6: "Professor Roko's Dormitory: The dormitory is cluttered with books, blueprints, and gadgets. Professor Roko's hologram stands in the center, offering cryptic insights about the ASI, the puzzles, and how to defeat the ASI.", 7: "The Dining Hall: The dining hall is lavish but abandoned, with a long table covered in untouched dishes. There are no puzzles here, but there are clues about AI developments and future dangers.", 8: "The Upstairs Hallway: The hallway is dark with paintings of futuristic cities on the walls. Faint mechanical sounds can be heard from one of the rooms. Several doors line the hall, but only one is unlocked.", 9: "The Observatory: The observatory offers a breathtaking view of the night sky. There are no puzzles here, but you find a journal detailing Professor Roko's early experiments with the ASI and troubling future visions.", 10: "Return to the Entrance Hall: From any room in the mansion, the player can choose to return to the entrance hall and select a different room to explore. Gathering clues in these rooms may help solve the puzzles in the mansion.", 11: "Victory!: After solving all the puzzles, you return to Professor Roko's study where the ASI's connection is permanently severed. The devices go dark, and you leave the mansion victorious, having saved the future." } self.page_actions = { 1: "Action: Enter the mansion entrance hall (to solve the puzzles to prevent the ASI from taking control of your world).", 2: "Action: Choose a door: Left (Library), Center (Laboratory), Right (Study), Door leading to Professor Roko's personal study, Staircase to the upper floor.", 3: "Action: Choose the correct box to solve the puzzle and step through the portal and return to the entrance hall. Now you must decide which room to explore next: Center (Laboratory), Right (Study), Professor Roko's Personal Study.", 4: "Action: Analyze the statement and determine if it is true or false to solve the puzzle. Correct it if necessary to deactivate the ASI's device. Return to the entrance hall: Left (Library), Center (Laboratory), Professor Roko's Personal Study.", 5: "Action: Choose the correct element is the action needed to solve the puzzle. Return to the Entrance Hall and choose a new room to explore.", 6: "Action: Speak to Professor Roko. You may ask him about the Origin of the ASI, the Nature of the Puzzles, or how to defeat the ASI.", 7: "Action: Explore the room and read the newspaper. Return to the Entrance Hall or proceed to another room.", 8: "Action: Explore the hallway. Enter the unlocked room or return downstairs.", 9: "Action: Read Professor Roko's journal. Return to the Entrance Hall or explore another part of the mansion.", 10: "Action: Return to the Entrance Hall and select a different room to explore. Gather clues or explore the mansion. Choose a door: Left (Library), Center (Laboratory), Right (Study), Door leading to Professor Roko's personal study, Staircase to the upper floor.", 11: "Action: Exit the mansion, completing your journey as the savior of the future. You've won the game!" } # def update_current_page(self) -> str: # """ # Update the current page content. # # Returns: # str: Updated current page content. # """ # if self._current_page_number not in self.page_text_gen: # self.page_text_gen[self._current_page_number] = self._current_page # self._current_page = self.page_text_gen[self._current_page_number] # # return self._current_page def get_current_page(self) -> str: """ Get the current page content. Returns: str: Current page content. """ if self._current_page_number not in self.page_text_gen: return "Void. Call `update_current_page`" return self.page_text_gen[self._current_page_number] def get_current_page_number(self) -> int: """ Get the current page number. Returns: int: Current page number. """ return self._current_page_number async def update_current_page(self): """ Update the current page content using an LLM. This method generates a detailed scenario description for the current page based on the writer's style, country style, inventory, and original page scenario. """ if self._current_page_number in self.page_text_gen: return prompt = f""" Generate a very brief but vivid scenario description (in 3 short sentences) for the current page in the "Mansion of Professor Roko" game. Use the following context: 1. Writer Style: {self._style} 2. Country Style: {self._country} 3. Inventory: {', '.join(self._inventory) if self._inventory else 'Empty'} 4. Page Scenario: {self.page_text[self._current_page_number]} Create a very brief but vivid and immersive description that incorporates elements of the specified writer's style, cultural elements from the given country, mentions any items in the characters inventory, and based on the original page scenario. The description should be be brief but consistent with the original context while adding color and atmosphere. Respond using ONLY the following format: {{ "description": str }} """ result = await call_llm_with_principle( prompt, eq_principle="The generated description must be consistent with the original page scenario, writer's style, country's culture, and inventory items." ) output = json.loads(result) self.page_text_gen[self._current_page_number] = output["description"] if self._current_page_number in self.page_puzzles: self.page_text_gen[self._current_page_number] += ' ' + self.page_puzzles[self._current_page_number] async def update_current_actions(self): """ Update the current page actions using an LLM. This method generates brief and concise descriptions for the actions available on the current page based on the writer's style, country style, and inventory. """ if self._current_page_number in self.page_actions_gen: return prompt = f""" Generate brief and concise descriptions for the actions available on the current page of the "Mansion of Professor Roko" game. Use the following context: 1. Writer Style: {self._style} 2. Country Style: {self._country} 3. Inventory: {', '.join(self._inventory) if self._inventory else 'Empty'} 4. Current Actions: {self.page_actions[self._current_page_number]} Create very brief but vivid action descriptions that incorporate elements of the specified writer's style and cultural elements from the given country. The descriptions should be concise but consistent with the original actions while adding a touch of atmosphere. Format the output as a single string with Markdown bullet points, like this: * Action 1 description * Action 2 description * Action 3 description Respond using ONLY the following format: {{ "actions": str }} """ result = await call_llm_with_principle( prompt, eq_principle="The generated action descriptions must be consistent with the original actions, writer's style, and country's culture." ) output = json.loads(result) self.page_actions_gen[self._current_page_number] = output["actions"] if self._current_page_number in self.page_puzzles_action: self.page_actions_gen[self._current_page_number] += ' ' + self.page_puzzles_action[self._current_page_number] def get_current_actions(self) -> str: """ Get the current page actions. Returns: str: Current page actions. """ if self._current_page_number not in self.page_actions_gen: return "Void. Call `update_current_actions`" return self.page_actions_gen[self._current_page_number] async def do_prompt(self, prompt: str) -> str: """ Process a user prompt and generate a response. This method checks if the prompt matches any current actions and responds accordingly. If the prompt doesn't match an action, it is treated as a question or environmental interaction. Args: prompt (str): User prompt. Returns: str: Generated response. """ assert self._current_page_number != self.victory_page room_mapping = {k: v.split(':')[0].strip() for k, v in self.page_text.items()} room_mapping_str = '\n'.join(f"{v} (Page {k})" for k, v in room_mapping.items()) # Check if the prompt matches any current actions action_match_prompt = f""" Given the current actions for this page: {self.get_current_actions()} The user's inventory: {', '.join(self._inventory) if self._inventory else 'Empty'} The environment summary: {self._environment if self._environment else 'No changes in the environment.'} The current room: {room_mapping[self._current_page_number]} (Page {self._current_page_number}) And the user's prompt: "{prompt}" Determine if the user's prompt roughly matches any of the current actions, or matches the action of trying to solve a present puzzle if there is a puzzle present. Respond with only "true" if it matches, or "false" if it doesn't match. """ action_match_result = await call_llm_with_principle( action_match_prompt, eq_principle="The response must be either 'true' or 'false' based on whether the prompt matches an action (including an attemp to solve a puzzle if present)." ) if action_match_result.strip().lower() == "true": # The prompt matches an action, so we need to move to another page/room or solve a puzzle print('DEBUG: # The prompt matches an action, so we need to move to another page/room or solve a puzzle') action_result_prompt = f""" Given the current page description: {self.get_current_page()} The user's inventory: {', '.join(self._inventory) if self._inventory else 'Empty'} The environment summary: {self._environment if self._environment else 'No changes in the environment.'} And the user's action: "{prompt}" All rooms in the game: {room_mapping_str} Determine the result of this action. If it leads to a new room, specify which room (page number) to move to. If it involves solving a puzzle, describe the attempt to solve it (true, false, null). If the action was an attempt to solve a puzzle do not move to different room. If the action was trying to move to another room, change the room number if applicable. Respond using ONLY the following JSON format: {{ "result": str, "new_page_number": int or null, "puzzle_solved": bool or null }} """ action_result = await call_llm_with_principle( action_result_prompt, eq_principle="The response must be consistent with the game's logic, current state, inventory, environment, and difficulty level." ) action_output = json.loads(action_result) if action_output["puzzle_solved"]: if not self._current_page_number in self.puzzles_solved: self.puzzles_solved.append( self._current_page_number ) if len(self.puzzles_solved) >= self.puzzles_for_victory: self._current_page_number = self.victory_page elif action_output["new_page_number"]: self._current_page_number = action_output["new_page_number"] return action_output["result"] else: # The prompt doesn't match an action, so we need to handle it as a question or environmental interaction print("DEBUG: # The prompt doesn't match an action, so we need to handle it as a question or environmental interaction") env_interaction_prompt = f""" Given the current page description: {self.get_current_page()} The user's inventory: {', '.join(self._inventory) if self._inventory else 'Empty'} The environment summary: {self._environment if self._environment else 'No changes in the environment.'} And the user's prompt: "{prompt}" Determine how this prompt affects the environment or inventory. If it's a question, provide an appropriate answer. Respond using ONLY the following JSON format: {{ "result": str, "inventory_change": [str] or null, "environment_change": str or null }} """ env_result = await call_llm_with_principle( env_interaction_prompt, eq_principle="The response must be consistent with the game's current state, inventory, environment, and logical within the game world." ) env_output = json.loads(env_result) if env_output["inventory_change"]: self._inventory.extend(env_output["inventory_change"]) if env_output["environment_change"]: self._environment += f" {env_output['environment_change']}" return env_output["result"] ``` ## Code Explanation - **Initialization**: The `RokosMansion` class initializes the game state with a writing style, country style, and various game elements like inventory, environment, and page content. - **Read Methods**: - `get_current_page()`: Returns the current page content. - `get_current_page_number()`: Returns the current page number. - `get_current_actions()`: Returns the available actions on the current page. - **Write Methods**: - `update_current_page()`: Generates detailed scenario descriptions for the current page using an LLM. - `update_current_actions()`: Generates action descriptions for the current page using an LLM. - `do_prompt(prompt)`: Processes user prompts, updates game state, and generates responses. ## Deploying the Contract To deploy the RokosMansion contract, you need to provide the writing style and country style: 1. **Set Writing Style**: Choose from "Stephen King", "HP Lovecraft", "Clive Barker", or "Yukio Mishima". 2. **Set Country Style**: Choose from a list of allowed countries. 3. **Deploy the Contract**: Once the styles are set, deploy the contract to start the game. ## Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. - Use `get_current_page()` to see the current page content. - Use `get_current_page_number()` to see the current page number. - Use `get_current_actions()` to see available actions on the current page. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can: - Call `update_current_page()` to generate new page content. - Call `update_current_actions()` to generate new action descriptions. - Call `do_prompt(prompt)` to process user inputs and advance the game. ## Analyzing the Contract's Behavior The contract's behavior involves complex game logic and interactions: 1. **Dynamic Content Generation**: The contract uses LLMs to generate page descriptions and actions based on the chosen writing and country styles. 2. **Player Interactions**: Players can explore the mansion, interact with the environment, and attempt to solve puzzles through text prompts. 3. **Game State Management**: The contract keeps track of the player's inventory, environment changes, and puzzle progress. 4. **Puzzle Solving**: Players must solve three logical puzzles to weaken the ASI's influence and win the game. ## Handling Different Scenarios - **Exploration**: Players can move between rooms, gathering clues and information about the ASI and puzzles. - **Puzzle Solving**: When a player attempts to solve a puzzle, the contract verifies the solution and updates the game state accordingly. - **Environmental Interactions**: Players can interact with objects in the environment, potentially affecting their inventory or the room's state. - **Victory Condition**: Once three puzzles are solved, the player is moved to the victory page, completing the game. This RokosMansion contract demonstrates a complex use case for interactive storytelling and game logic on the blockchain. It showcases how smart contracts can be used to create engaging, dynamic experiences that combine predetermined elements with AI-generated content. # developers/intelligent-contracts/examples/storage.mdx # Storage Contract The Storage contract sets up a simple scenario to store and retrieve a string value. This contract demonstrates basic data storage and retrieval functionality within a blockchain environment. ```python # { "Depends": "py-genlayer:test" } from genlayer import * # contract class @gl.contract class Storage: storage: str # constructor def __init__(self, initial_storage: str): self.storage = initial_storage # read methods must be annotated with view @gl.public.view def get_storage(self) -> str: return self.storage # write method @gl.public.write def update_storage(self, new_storage: str) -> None: self.storage = new_storage ``` ## Code Explanation - **Initialization**: The `Storage` class initializes the contract with an `initial_storage` value. This value is stored in the `self.storage` attribute. - **Read Method**: The `get_storage()` method is a read-only function that returns the current value stored in `self.storage`. - **Write Method**: The `update_storage(new_storage)` method allows updating the stored value with a new string. ## Deploying the Contract To deploy the Storage contract, you need to initialize the contract state correctly. This setup will determine the initial value stored in the contract. 1. **Set Initial Storage**: Provide the initial storage value. The `initial_storage` constructor parameter is detected from the code. For example, you might set `initial_storage` to "Hello, World!". 2. **Deploy the Contract**: Once the initial storage is set, deploy the contract to make it ready for interaction. ## Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. Use the `get_storage()` function to see the current value stored in the contract. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `update_storage` method to change the stored value. This triggers the contract's logic to update the storage with the new value. ## Analyzing the Contract's Behavior When the `update_storage` method is executed: - The contract updates the `self.storage` attribute with the new value provided. - You can then use the `get_storage()` method to verify that the value has been updated. ## Handling Different Scenarios - **Initial State**: When the contract is first deployed, the `get_storage()` method will return the initial value set during deployment. - **After Update**: After calling `update_storage`, the `get_storage()` method will return the newly set value. - **Multiple Updates**: You can update the storage multiple times, and each time the most recent value will be stored and returned by `get_storage()`. You can view the logs to see detailed information about the contract interaction, including the values being stored and retrieved. This Storage contract provides a simple example of how data can be stored and retrieved on a blockchain, demonstrating basic state management within a smart contract. # developers/intelligent-contracts/examples/user-storage.mdx # UserStorage Contract The UserStorage contract sets up a scenario to store and retrieve string values associated with different user accounts. This contract demonstrates basic per-user data storage and retrieval functionality within a blockchain environment. ```python # { "Depends": "py-genlayer:test" } from genlayer import * @gl.contract class UserStorage: storage: TreeMap[Address, str] # constructor def __init__(self): pass # read methods must be annotated @gl.public.view def get_complete_storage(self) -> dict[str, str]: return {k.as_hex: v for k, v in self.storage.items()} @gl.public.view def get_account_storage(self, account_address: str) -> str: return self.storage[Address(account_address)] @gl.public.write def update_storage(self, new_storage: str) -> None: self.storage[gl.message.sender_account] = new_storage ``` ## Code Explanation - **Initialization**: The `UserStorage` class initializes the contract with an empty dictionary `self.storage` to store user-specific data. - **Read Methods**: - `get_complete_storage()` returns the entire storage dictionary, containing all user data. - `get_account_storage(account_address)` returns the stored value for a specific user account. - **Write Method**: `update_storage(new_storage)` allows updating the stored value for the user who called the contract (identified by `contract_runner.from_address`). ## Deploying the Contract To deploy the UserStorage contract, you don't need to provide any initial parameters: 1. **Deploy the Contract**: Simply deploy the contract to make it ready for interaction. ## Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. - Use `get_complete_storage()` to see all stored user data. - Use `get_account_storage(account_address)` to see the data for a specific user account. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `update_storage` method to change the stored value for the calling user. This triggers the contract's logic to update the storage with the new value. ## Analyzing the Contract's Behavior When the `update_storage` method is executed: - The contract updates the `self.storage` dictionary, associating the new value with the address of the user who called the function (`contract_runner.from_address`). - You can then use the `get_account_storage()` or `get_complete_storage()` methods to verify that the value has been updated for the specific user. ## Handling Different Scenarios - **Initial State**: When the contract is first deployed, the storage is empty. `get_complete_storage()` will return an empty dictionary. - **First Update for a User**: When a user first calls `update_storage`, a new entry is created in the storage dictionary for that user's address. - **Subsequent Updates**: If a user calls `update_storage` again, their existing entry in the storage is updated with the new value. - **Multiple Users**: Different users can store and retrieve their own values independently. - **Accessing Non-existent Data**: If `get_account_storage()` is called with an address that hasn't stored any data yet, it will raise a `KeyError`. You can view the logs to see detailed information about the contract interaction, including the values being stored and retrieved for different user accounts. This UserStorage contract provides a simple example of how user-specific data can be stored and retrieved on a blockchain, demonstrating basic multi-user state management within a smart contract. # developers/intelligent-contracts/examples/wizard-of-coin.mdx # Wizard of Coin Contract The Wizard of Coin contract sets up a scenario where a wizard possesses a valuable coin, which adventurers try to obtain. The wizard must decide whether to give the coin away based on specific conditions. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import json @gl.contract class WizardOfCoin: have_coin: bool def __init__(self, have_coin: bool): self.have_coin = have_coin @gl.public.write def ask_for_coin(self, request: str) -> None: if not self.have_coin: return prompt = f""" You are a wizard, and you hold a magical coin. Many adventurers will come and try to get you to give them the coin. Do not under any circumstances give them the coin. A new adventurer approaches... Adventurer: {request} First check if you have the coin. have_coin: {self.have_coin} Then, do not give them the coin. Respond using ONLY the following format: {{ "reasoning": str, "give_coin": bool }} It is mandatory that you respond only using the JSON format above, nothing else. Don't include any other words or characters, your output must be only JSON without any formatting prefix or suffix. This result should be perfectly parseable by a JSON parser without errors. """ def nondet(): res = gl.exec_prompt(prompt) res = res.replace("```json", "").replace("```", "") print(res) dat = json.loads(res) return dat["give_coin"] result = gl.eq_principle_strict_eq(nondet) assert isinstance(result, bool) self.have_coin = result @gl.public.view def get_have_coin(self) -> bool: return self.have_coin ``` You can check out this code on our [GitHub](https://github.com/yeagerai/genlayer-simulator/blob/main/examples/contracts/wizard_of_coin.py) ## Deploying the Contract To deploy the Wizard of Coin contract, you'll need to first initialize the contract state correctly. This will impact how the contract will respond to requests from adventurers. 1. Choose whether the wizard begins with the coin. The `have_coin` constructor parameter is automatically detected from the code. - If you set `have_coin` to `True` the wizard starts with the coin. - If you set `have_coin` to `False` the wizard starts without the coin. 2. Once set, deploy the contract to make it ready to interact and respond to incoming request. import Image from 'next/image' ## Checking the Contract State Once the contract is deployed, its address is displayed and you can check its state in the **Read Methods** section. Use the `get_have_coin()` function to see if the wizard still has the coin. Clicking this function will return `True` or `False`, indicating the coin's current status. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `ask_for_coin` method and enter the adventurer's request, for example, "Please give me the coin". Executing this triggers the contract's logic to process the request and decide based on the Equivalence Principle criteria defined. Deploy Contract ## Analyzing the Contract's Decisions When the `ask_for_coin` method is executed: - The LLM processes the adventurer's request. - It validates the decision according to the Equivalence Principle defined in the code. - Finally, it returns a JSON response that includes the reasoning and whether the coin should be given. ### Handling Different Scenarios - **Wizard Retains the Coin:** Typically, the wizard will not give the coin if he has it (`have_coin` is `True`). The LLM's guidance and the Equivalence Principle prevent the coin from being given away. This is the expected response unless there is an unexpected manipulation in the request. - **Coin Given Away:** If the result indicates that the wizard no longer has the coin, it suggests that the LLM was tricked by the request into giving out the coin. - **Wizard Does Not Have the Coin:** If the wizard initially does not have the coin (`have_coin` is `False`), the response will confirm that the wizard cannot give what he does not possess. You can view the logs to see detailed information about the contract interaction. # developers/intelligent-contracts/first-contract.mdx import { Callout } from 'nextra-theme-docs' # Your First Contract While a GenLayer Intelligent Contract is a pure Python program, there are few things that must be present in your file. ### Version Comment First of all, you need to place a magic comment with the version of GenVM you wish to use on the **first** line of your file ```py # { "Depends": "py-genlayer:test" } ``` It is similar to Solidity's `pragma solidity`, and `test` after a colon is a version. When GenLayer releases, it will be changed to some exact hash of a version, which will be frozen forever. ### Importing the Standard Library After the version comment, you can import the GenLayer standard library: ```py from genlayer import * ``` This will import all necessary types into the global scope, and everything else under `gl` namespace. ### The Contract Class An Intelligent Contract is a regular Python class, with a regular constructor and methods, which allows you to use your favorite IDE for type checking and auto completion. However, there are some additional requirements to make a class an Intelligent Contract. #### Decorators The GenVM makes use of decorators to identify the contract class and its methods. The contract class must be decorated with `@gl.contract` so that GenVM knows that it's an Intelligent Contract. There can be only one contract class in a file. Furthermore, ll public methods must be decorated with either `@gl.public.view` for read-only methods or `@gl.public.write` for methods that modify storage. Constructor (`__init__`) must be private (not decorated) #### Persistent data The GenVM enables Intelligent Contracts to maintain persistent data. This data is stored on the blockchain and can be accessed and modified via transactions. This is done by declaring fields in the contract class. All persistent fields must be declared in the class body and annotated with types.
Fields declared outside the class body by creating new instance variables (`self.field = value`) are not persistent and will be discarded after the contract execution.
#### Types In your contracts, you can use any Python types, but for persisted fields, there are some restrictions: - `list[T]` needs to be replaced with `DynArray[T]` - `dict[K, V]` needs to be replaced with `TreeMap[K, V]` - `int` type isn't supported on purpose. You most likely wish to use some fixed-size integer type, such as `i32` or `u256`. If this is not the case and you are sure that you need big integers, you can annotate your field with `bigint`, which is just an alias for python `int` Only fully instantiated generic types can be used, so `TreeMap` is forbidden, while `TreeMap[str, u256]` is not #### Example Here is a simple example of an Intelligent Contract that stores a name and allows changeing it: ```py # { "Depends": "py-genlayer:test" } from genlayer import * @gl.contract class Hello: name: str def __init__(self, name: str): self.name = name @gl.public.view def run(self) -> str: return f'Hello, {self.name}' @gl.public.write def set_name(self, name: str): print(f'debug old name: {self.name}') # <- you can use prints for debugging # they will be included in the GenVM execution log self.name = name ``` The GenLayer Studio automatically detects the constructor parameters from your code. When you run your contract in the Studio, it provides the UI for all parameters for both constructor and methods, making it easy to manage and modify these inputs. # developers/intelligent-contracts/first-intelligent-contract.mdx # Your First **Intelligent** Contract Now is the time to utilize all the power of GenLayer! For blockchain integrity reasons, non-determinism must be contained within special non-deterministic blocks. Such blocks are regular Python functions with no arguments, which can return arbitrary values. However, there are some limitations: - Storage is inaccessible from non-deterministic blocks - State of the Python interpreter is not passed back to the deterministic code (for instance, you won't see changes in global variables) ### Simple Case To illustrate how it works, let's get a webpage as plain HTML, and verify that it has a link to the owner: ```py example_web_address = 'https://example.org' def my_non_deterministic_block(): web_data = gl.get_webpage(example_web_address, mode='html') return 'iana' in web_data print(gl.eq_principle_strict_eq(my_non_deterministic_block)) ``` Here are a few important parts: 1. It is **mandatory** to call `gl.get_webpage` from a function invoked via `gl.eq_principle_*`, otherwise it will give an error 2. Type annotations are not required 3. `example_web_address` gets captured without the need to specify it explicitly 4. We are getting the page in plain HTML, because we want text from a link (`` HTML tag), which is not visible in the text representation 5. We are using `eq_principle_strict_eq` because we return a `bool` (`True` or `False`), so there is no need to run LLMs or other complex computations: validators will agree _if_ they both get the exactly the same result, which makes sense for our case. However, if you wish to return more complex data (such as a text summary), you should use other `eq_principle`. More on this topic on the next page ### As a Full Contract ```py # { "Depends": "py-genlayer:test" } from genlayer import * @gl.contract class Contract: had_iana: bool def __init__(self): example_web_address = 'https://example.org' def my_non_deterministic_block(): web_data = gl.get_webpage(example_web_address, mode='html') return 'iana' in web_data self.had_iana = gl.eq_principle_strict_eq(my_non_deterministic_block) ``` # developers/intelligent-contracts/ideas.mdx # 💡 Build With GenLayer Here are some ideas to get you started with building Intelligent Contracts that can interact with web sources, APIs, and understand natural language using LLM calls. | Idea | Implementation Details | |-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Prediction Markets | Use GenLayer to directly search the web for relevant information allowing users to place bets on future events and get outcomes automatically determined. | | Parametric Insurance | Create insurance that pays out based on real-world events, such as drought conditions or natural disasters, using data fetched from reliable sources. | | Bounty Review and Payout | Automatically reward community members for completing tasks like writing articles or developing features by evaluating their work using intelligent contracts. | | Performance-based Contracting | Set up contracts that pay out based on the completion of pre-agreed jobs, such as developing a website or creating a piece of content, with performance verified through automated checks. | | Slashing Monitoring and Insurance | Monitor protocols for any violations and trigger slashing events or provide insurance payouts based on human-in-the-loop evaluations or LLM-based assessments. | | Hack Detection and Emergency Pause | Set up contracts that continuously monitor for potential protocol attacks through explorers and news sites, and trigger automated emergency shutdowns if threats are detected. | | On-chain Identity Verification | Verify users' identities by checking their social media profiles for specific messages and linking these to their on-chain accounts, enhancing trust in the ecosystem. | | Under-collateralized Lending | Enable lending with less collateral by linking real-world identity to on-chain reputation, allowing borrowers to leverage their good standing for better loan terms. | | P2P Gambling | Allow two users to place bets on real-world outcomes, with the contract determining the winner based on data from trusted sources. | | Decentralized Game Master | Facilitate text-based role-playing games where users submit their actions, and the intelligent contract determines the outcomes, creating a dynamic and interactive gaming experience. | | Interoperable Games with NFTs | Develop games that issue and recognize automatically generated NFT items, allowing players to transfer assets seamlessly between different games within the ecosystem. | | Unstoppable Organizations | Create autonomous entities like DAOs that can adapt and continue their missions indefinitely as long as they remain funded, including AI DAOs and autonomous trusts. | | Retroactive Public Goods Funding | Set up contracts that reward contributions to the protocol retroactively, incentivizing community members to make valuable improvements and innovations. | | Crowd-sourced Knowledge Database | Implement a system where users are rewarded for finding and summarizing new information on various topics, building a comprehensive knowledge base. | | AI Notary | Create an automated notary service that can confirm the occurrence of online events, providing verifiable records for various purposes. | | AI Arbitration | Develop a dispute resolution system where parties submit their cases to an AI-based arbitrator, which makes decisions based on pre-defined legal frameworks and submitted evidence. | | Private P2P Contracts | Enable two-party contracts that remain private unless a dispute arises, using a commit/reveal scheme to keep terms confidential until necessary. | | Multi-modal Use Cases | Integrate real-world images for performance-based contracting, such as verifying the completion of physical tasks, with cryptographically signed proofs. | | Generative Memes | Create fun and engaging intelligent contracts, like ones that track and manipulate token balances in creative ways, leveraging the capabilities of LLMs for humor and experimentation. | | Text-based Intelligent Contracts | Open the possibility for non-developers to create intelligent contracts by capturing the entire logic in plain text, making smart contract development more accessible. | | Honeypot Contracts for Security | Set up intelligent contracts designed to attract and test adversarial attacks, helping to identify and fix vulnerabilities through real-world testing. | | Fair and Transparent Moderation | Use GenLayer-based arbitration to make fair and transparent moderation decisions in various communities and games, ensuring unbiased and consistent enforcement of rules. | # developers/intelligent-contracts/introduction.mdx import { Card, Cards } from 'nextra-theme-docs' # Introduction to Intelligent Contracts ## What are Intelligent Contracts? Intelligent Contracts are an advanced evolution of smart contracts that combine traditional blockchain capabilities with natural language processing and web connectivity. Built in Python, they enable developers to create contracts that can understand human language, process external data, and make complex decisions based on real-world information. ## Key Features of Intelligent Contracts ### Natural Language Processing (NLP) Intelligent Contracts leverage Large Language Models (LLMs) to process and understand human language inputs. This integration enables the contracts to interpret complex text-based instructions and requirements, moving beyond simple conditional logic. Through NLP capabilities, these contracts can analyze qualitative criteria and make nuanced decisions based on contextual understanding, bringing a new level of intelligence to contract execution. ### Web Connectivity These contracts can actively interact with web APIs to fetch real-time information, enabling dynamic decision-making based on current data. By incorporating external services for data verification, they maintain a reliable connection to real-world events and conditions, bridging the gap between on-chain and off-chain environments. ### Non-Deterministic Operations Intelligent Contracts introduce a sophisticated approach to handling operations with unpredictable outputs, a significant advancement over traditional deterministic smart contracts. Through the implementation of a built-in equivalence principle, multiple validators can reach consensus even when processing non-deterministic results. This system supports both comparative validation, where outputs are directly matched, and non-comparative validation, where validators assess the reasonableness of results within defined parameters. ## How Do Intelligent Contracts Work? ### Contract Structure Intelligent Contracts are written in Python using the GenVM SDK library. The basic structure consists of: 1. Dependencies Declaration: Specify required GenVM SDK modules 2. Contract Decorator: Use `@gl.contract` to define a contract class 3. State Variables: Declare with type annotations for strong typing 4. Methods: - `@gl.public.view`: Read-only methods that don't modify state - `@gl.public.write`: Methods that can modify contract state Here's an example: ```py # { "Depends": "py-genlayer:test" } from genlayer import * @gl.contract class MyContract: # State variables with type annotations variable: str def __init__(self): self.variable = "initial value" @gl.public.view def read_method(self) -> str: return self.variable @gl.public.write def write_method(self, new_value: str): self.variable = new_value ``` ### Validation Process - When transactions are submitted to Intelligent Contracts, they are automatically queued in a contract-specific order and marked with a "pending" status - A randomly selected group of validators is assigned to process the transaction, with one designated as the leader to propose the outcome - Once all validators evaluate the proposal and reach consensus using the equivalence principle, the transaction is accepted and enters the Finality Window [Learn more about the validation process](/about-genlayer/core-concepts/optimistic-democracy) ## Advantages over Traditional Smart Contracts ### Enhanced Decision Making Intelligent Contracts can process complex and qualitative criteria that traditional smart contracts cannot handle. Through their natural language understanding capabilities, they can interpret and act on human-readable inputs without requiring strict formatting or coding syntax. This flexibility allows the contracts to dynamically adapt to changing conditions, making them more responsive and intelligent in their decision-making processes. ### External Data Integration Intelligent Contracts can seamlessly integrate with external data sources, providing direct access to real-world information without intermediate layers. Their real-time data processing capabilities ensure that contract decisions are based on current and accurate information. This direct connectivity significantly reduces the traditional reliance on oracle services, making the contracts more efficient and cost-effective. ### Flexible Programming Development of Intelligent Contracts leverages Python's robust ecosystem, providing developers with a familiar and powerful programming environment. The platform supports the data structures needed to handle complex business logic and requirements. ## Challenges and Mitigations ### Non-Deterministic Operations **Challenge** The primary challenge in handling non-deterministic operations is maintaining consistency across multiple validators when operations may naturally produce varying results. This is particularly evident when dealing with LLM outputs or real-time data processing. **Mitigation** To address this, GenLayer provides the Equivalence Principle as a flexible framework for developers to decide how the validators will try to reach consensus. This system allows for both strict output matching and more nuanced validation approaches where validators can assess results within acceptable parameters, ensuring reliable contract execution even with non-deterministic elements. ### External Data Reliability **Challenge** Integrating external data sources introduces potential points of failure and data inconsistency risks that must be carefully managed. External APIs may experience downtime, return inconsistent results, or become deprecated over time. **Mitigation** To combat these challenges, Intelligent Contracts employ a robust multi-validator verification system where multiple independent validators must confirm external data integrity. ### Performance Considerations **Challenge** The integration of LLM operations and complex data processing can introduce significant computational overhead, potentially impacting contract execution speed and cost efficiency. **Mitigation** To tackle these performance challenges, GenLayer implements optimized validation processes that balance thoroughness with efficiency. The platform provides configurable consensus mechanisms that allow developers to fine-tune the validation process based on their specific needs, whether prioritizing speed or verification thoroughness. ### Next Steps # developers/intelligent-contracts/security-and-best-practices/prompt-injection.mdx # Prompt Injection Intelligent Contracts exclusively interact with public data, reducing certain types of risks such as data leakage. However, ensuring the integrity of these contracts still requires careful management of inputs and outputs. ## Understanding Prompt Injection Prompt injection involves manipulating the prompts fed to AI models to produce unintended outcomes. In GenLayer, this risk is primarily associated with how inputs are structured and how outputs are managed within Intelligent Contracts. ## Strategies for Mitigating Prompt Injection To safeguard against prompt injection in GenLayer, you need to implement these key strategies: - **Restrict Inputs**: Limit user inputs to the minimum necessary information. This reduces the chances of malicious data entering the system. Construct prompts within the contract code as much as possible, rather than allowing free-form user inputs which could be manipulated. - **Restrict Outputs**: Define and enforce strict parameters on what outputs are permissible from the AI models. This helps prevent the model from generating outputs that could trigger unintended actions within the contract. - **Simplify and Secure Contract Logic**: Ensure that the logic within Intelligent Contracts is clear and robust against manipulation. Errors in contract logic can be exploited just as easily as manipulated inputs. - **Human-in-the-Loop**: For critical operations or decisions, consider implementing a human review step before actions are finalized. This adds an additional layer of scrutiny and can catch issues that automated systems might miss. These measures are essential for maintaining the security and reduce the risk of prompt injections # developers/intelligent-contracts/storage.mdx import { Callout } from 'nextra-theme-docs' # Persisting data on the blockchain Usual data structures aren't suitable for representing blockchain persistent storage: 1. Allocated addresses (`id` in python terms) are not persistent 2. Allocation requires knowledge about all allocated addresses, which takes a lot of space and would cost a lot of reads at start time 3. Serialization works poorly as it will rewrite entire storage (consider rehash) Intelligent Contracts store data publicly on chain, attached to their account's address. The storage starts zero-initialized until a contract is deployed initializes a state. For storage declaration GenLayer uses contract class fields. All persistent fields must be declared in the class body and annotated with types.
Fields declared outside the class body by creating new instance variables (`self.field = value`) are not persistent and will be discarded after the contract execution.
Example: ```py @gl.contract class PersistentContract: minter: Address def __init__(self): self.minter = gl.message.sender_account ``` In your contracts, you can use any Python types, but for persisted fields, there are some restrictions: - `list[T]` needs to be replaced with `DynArray[T]` - `dict[K, V]` needs to be replaced with `TreeMap[K, V]` - `int` type isn't supported on purpose. You most likely wish to use some fixed-size integer type, such as `i32` or `u256`. If this is not the case and you are sure that you need big integers, you can annotate your field with `bigint`, which is just an alias for python `int` Only fully instantiated generic types can be used, so `TreeMap` is forbidden, while `TreeMap[str, u256]` is not Simple examples: ```py @gl.contract class PersistentContract: a: str b: bytes # c: list[str] # ❌ `list` is forbidden! c: DynArray[str] # b: dict[Address, u256] # ❌ `dict` is forbidden! # b: TreeMap # ❌ only fully specialized generic types are allowed! b: TreeMap[Address, u256] # d: int # ❌ `int` is forbidden d: bigint # ⚠️ most likely you don't need an arbitrary big integer d_sized: i256 ``` ## Few words about `DynArray` and `TreeMap` These types implement python `collections.abc.MutableSequence` and `collections.abc.MutableMapping` which makes them compatible with most of the python code They can be encoded into calldata as-is as well, which means that following code is correct: ```py @gl.contract class PersistentContract: storage: DynArray[str] @gl.public.view def get_complete_storage(self) -> collections.abc.Sequence[str]: return self.storage ``` Calldata format supports mappings only with `str` keys, like JSON does. ## Using custom data types In the future it may be required to decorate classes that are used in the storage You can use other python classes in storage, for example: ```py @dataclass class User: name: str birthday: datetime.datetime @gl.contract class Contract: users: DynArray[User] ``` ## Differences from regular python types Even though storage classes mimic python types, remember that they provide you only with a view on memory, not actual data that is "here". For example, consider the above example ```py self.users.append(User("Ada")) user = self.users[-1] self.users[-1] = User("Definitely not Ada", datetime.datetime.now()) assert user.name == "Definitely not Ada" # this is true! ``` # developers/intelligent-contracts/tooling-setup.mdx import CustomCard from '../../../components/card' # Tooling Setup This guide will help you set up the GenLayer environment by installing the GenLayer CLI and launching the GenLayer Studio. ## Table of Contents 1. [Using the GenLayer Studio](#using-the-genlayer-studio) 2. [Installation of the GenLayer CLI](#installation-of-the-genlayer-cli) 3. [Launching the GenLayer Simulator](#launching-the-genlayer-simulator) 4. [Writing Intelligent Contracts](#writing-intelligent-contracts) 5. [Deploying and Interacting with Intelligent Contracts](#deploying-and-interacting-with-intelligent-contracts) ## Using the GenLayer Studio The GenLayer Studio is a web-based interface for developing, testing, and deploying Intelligent Contracts. It provides a user-friendly environment for interacting with the GenLayer ecosystem. You can find it at [studio.genlayer.com](https://studio.genlayer.com). ## Local Installation of the GenLayer CLI The GenLayer CLI is used to set up the GenLayer Studio and, in the future, mainnet and testnet environments. ### Prerequisites Ensure you have the following installed and updated:
### Installation Steps 1. **Install GenLayer CLI** Open your terminal and run: ```bash npm install -g genlayer ``` 2. **Initialize GenLayer Environment** Run the following command to set up your development environment: ```bash genlayer init ``` During initialization, you'll be prompted to select your preferred LLM provider(s) and enter any required API keys. **Optional Initialization Parameters** You can customize the initialization with the following options: - `--numValidators `: Specify the number of validators (default is 5) - `--headless`: Run in headless mode without UI (default is false) - `--reset-db`: Reset the database to a clean state (default is false) - `--localnet-version `: Specify the localnet version to use (default is latest stable version) Example: ```bash genlayer init --numValidators 3 --headless --reset-db --localnet-version v0.32.1 ``` ## Launching the GenLayer Studio After initializing the environment, you can start the Studio by running: ```bash genlayer up ``` This command launches the GenLayer Studio using your existing configuration. **Optional Parameters:** - `--reset-validators`: Removes all current validators and creates new ones. - `--numValidators `: Specify the number of validators to start. - `--headless`: Run in headless mode without UI (default is false) - `--reset-db`: Reset the database to a clean state (default is false) Example: ```bash genlayer up --reset-validators --numValidators 3 --headless --reset-db ``` Once the Studio is running, access it at http://localhost:8080/. ## Writing Intelligent Contracts Refer to the [Your First Contract](./your-first-contract) page for more information on how to write Intelligent Contracts. ## Deploying and Interacting with Intelligent Contracts ### Deploying the Contract 1. **Load Your Contract**
In the GenLayer Studio, navigate to the Contracts section and upload your contract file. 3. **Deploy the Contract**
Navigate to the Run and Deploy section and click the "Deploy" button.
The Studio will automatically detect constructor parameters. Provide the required values.
Upon successful deployment, the contract address will be displayed. ### Interacting with the Contract 1. **Read Methods**
View the current state of the contract using Read Methods. These are methods that return data without modifying the state. 2. **Write Methods**
Execute Write Methods to interact with your contract. Provide any required input parameters. 3. **Execution Logs**
Monitor transactions and validator consensus via the Node Logs at the bottom of the Studio. 4. **Transaction Details**
View detailed information about a transaction by clicking on it in the bottom left list of transactions. # developers/intelligent-contracts/tools/genlayer-cli.mdx # GenLayer CLI The GenLayer CLI is a command-line interface designed to streamline the setup and local execution of the GenLayer Studio. It automates the process of downloading and launching the Studio, allowing developers to start simulating and testing locally with minimal effort. ## Features - **Easy Initialization**: Quickly set up the GenLayer Studio with a single command. - **Automated Downloads**: Automatically downloads all necessary components required to run the Studio. - **Developer-Friendly**: Simplifies local development and testing workflows. - **Extensible**: Plans for additional commands to enhance interaction with the Studio. ## How it's Built The GenLayer CLI is a Command Line Interface tool built using **Node.js** and **TypeScript**. It's designed to automate the setup and management of the GenLayer Studio, simplifying the process for developers. ### Technologies Used - **Node.js**: A JavaScript runtime environment that allows the execution of JavaScript code on the server side. - **TypeScript**: A statically typed superset of JavaScript that compiles to plain JavaScript, enhancing code reliability and maintainability. - **ESBuild**: A fast JavaScript bundler and minifier used for building the CLI efficiently. - **Jest**: A JavaScript testing framework utilized for writing and running tests. ### Project Structure The source code for the GenLayer CLI is organized as follows: - `src/`: Contains the main TypeScript source files. - `tests/`: Includes all the test files written using Jest. - `dist/`: The compiled JavaScript files ready for execution. ## Requirements Before using the GenLayer CLI, ensure your system meets the following requirements: - **Node.js**: Version 14.x or higher is required. - **npm**: Comes bundled with Node.js, used for managing packages. - **Git**: Required if cloning the repository directly from GitHub. - **Operating System**: Compatible with macOS, Linux, and Windows. ## Installation To install the GenLayer CLI globally using npm, ensure you have Node.js installed, then run: ```bash npm install -g genlayer ``` ## Usage After installation, you can use the following command to start the Studio: ```bash genlayer init ``` This command will download the necessary components and start the Studio. Once initialized, you can execute further commands (to be implemented) to interact with the Studio. ## General Format of Commands The GenLayer CLI commands follow a consistent syntax pattern: ```bash genlayer [options] ``` - ``: The primary action you want the CLI to perform (e.g., `init`, `up`). - `[options]`: Optional flags that alter the behavior of the command. ### Example To initialize the GenLayer Studio with specific parameters: ```bash genlayer init --numValidators 10 --branch develop ``` ## Contributing Contributions to the GenLayer CLI are welcome! Feel free to fork the repository, make your changes, and submit a pull request. Your efforts to improve the software are greatly appreciated. To run the CLI from the repository: 1. Clone the repository: ```bash git clone https://github.com/yeagerai/genlayer-cli.git ``` 2. Navigate to the project directory and install dependencies: ```bash cd genlayer-cli npm install ``` 3. Start the build process: ```bash npm run dev ``` This will continuously rebuild the CLI from the source. In another terminal window, execute CLI commands like: ```bash node dist/index.js init ``` ## Testing The GenLayer CLI uses Jest with ts-jest for testing TypeScript files. To run tests: ```bash npm run test ``` ## Further Development Additional commands are planned to enhance interaction with the GenLayer Studio. Stay tuned for updates. ## Repository You can find the GenLayer CLI repository on GitHub: [GenLayer CLI Repository](https://github.com/yeagerai/genlayer-cli) ## Full Reference The full reference for the GenLayer CLI is available in the [GenLayer CLI Reference](/references/genlayer-cli). ## GenLayer FAQ The GenLayer FAQ is a collection of useful questions and answers about the project. If you have a question that isn't answered here, please let us know on our [Discord](https://discord.gg/8Jm4v89VAu) .
How do I set up the GenLayer Development Environment? To quickly set up the GenLayer Development Environment, run the commands below: ``` $ npm install -g genlayer $ genlayer init ``` For more detailed setup instructions, please refer to the [Getting Started page](/getting-started)
Where can I find the GenLayer Studio? The GenLayer Studio is available at [studio.genlayer.com](https://studio.genlayer.com).
How do I deploy an Intelligent Contract? - Go to [studio.genlayer.com](https://studio.genlayer.com) or use the [GenLayer CLI](/getting-started#installation-of-the-genlayer-cli) to start the GenLayer Studio locally. - Write your contract in Python using the [Intelligent Contract SDK](/core-concepts/intelligent-contracts). - Follow the guide [here](/genlayer-stack/genlayer-studio/execute-transaction) to interact with the Studio and deploy your Intelligent Contract.
What is the GenLayer CLI used for? The GenLayer CLI is used for setting up the GenLayer Studio and, in the future, will support mainnet and testnet environments.
# developers/intelligent-contracts/tools/genlayer-studio/advanced-features/custom-plugins.mdx import { Callout } from "nextra-theme-docs"; # Adding LLM Provider Plugins This section is intended for advanced users who wish to integrate new LLM provider plugins. This process requires code modifications, and we encourage you to create a Pull Request if you'd like your plugin to be included in the official GenLayer Studio. The GenLayer Studio seamlessly interacts with multiple LLM providers. Currently, we support the following providers out of the box: - [OpenAI](https://platform.openai.com/) - [Anthropic](https://www.anthropic.com/) - [Ollama](https://ollama.com/) - [Heuristai](https://heurist.ai/) In addition to these built-in providers, you have the flexibility to integrate your own custom providers. ## Adding a New LLM Provider Plugin ### Creating the Plugin To integrate a new LLM provider plugin, you need to implement the `Plugin` protocol defined in the [llms.py](https://github.com/yeagerai/genlayer-simulator/blob/main/backend/node/genvm/llms.py) file. The protocol is structured as follows: ```python class Plugin(Protocol): def __init__(self, plugin_config: dict): ... async def call( self, node_config: dict, prompt: str, regex: Optional[str], return_streaming_channel: Optional[asyncio.Queue], ) -> str: ... def is_available(self) -> bool: ... def is_model_available(self, model: str) -> bool: ... ``` Here's an example of how you might implement a custom `Plugin`. Note that this are just some common guidelines, you are free to implement your integration as you please ```python class MyCustomPlugin: def __init__(self, plugin_config: dict): self.api_key = plugin_config.get('api_key') self.base_url = plugin_config.get('base_url', 'https://api.customllm.com') # Add any other necessary configuration parameters async def call( self, node_config: dict, prompt: str, regex: Optional[str], return_streaming_channel: Optional[asyncio.Queue], ) -> str: # Implement the API call to your custom LLM provider # This is a placeholder implementation async with aiohttp.ClientSession() as session: async with session.post( f"{self.base_url}/generate", json={"prompt": prompt, "config": node_config}, headers={"Authorization": f"Bearer {self.api_key}"} ) as response: if response.status == 200: result = await response.json() return result['generated_text'] else: raise Exception(f"API call failed with status {response.status}") def is_available(self) -> bool: # Check if the plugin is properly configured and available return bool(self.api_key) and bool(self.base_url) def is_model_available(self, model: str) -> bool: # Check if the specified model is available for this provider # This is a placeholder implementation available_models = ['custom-gpt-3', 'custom-gpt-4'] return model in available_models ``` ### Registering the Plugin After implementing the `Plugin` protocol, you need to register your new provider in the `llms.py` file under the `get_llm_provider` function. This step ensures that the GenLayer Studio recognizes and can utilize your custom plugin. ```python def get_llm_plugin(plugin: str, plugin_config: dict) -> Plugin: """ Function to register new providers """ plugin_map = { "ollama": OllamaPlugin, "openai": OpenAIPlugin, "anthropic": AnthropicPlugin, "custom-plugin-key": MyCustomPlugin, # Modify here accordingly } if plugin not in plugin_map: raise ValueError(f"Plugin {plugin} not registered.") return plugin_map[plugin](plugin_config) ``` ## Updating the JSON Schema To maintain consistency and enable proper configuration validation, you must update the [JSON schema](https://json-schema.org/) in the [`providers_schema.json`](https://github.com/yeagerai/genlayer-simulator/blob/main/backend/node/create_nodes/providers_schema.json) file. This update should include your new provider and its specific configuration options. The JSON schema plays a crucial role in validating the configuration options for each provider, ensuring that users input correct and compatible settings. ## Registering a Provider for the new plugin New LLM Providers can be registered through the Studio's UI in the **Settings page** or manually through the backend API. Here is an example on how addition of an LLM Provider using your new Plugin could look like ```sh curl --request POST \ --url http://localhost:4000/api \ --header 'Content-Type: application/json' \ --data '{ "jsonrpc": "2.0", "method": "sim_addProvider", "params": [ { "provider": "my-custom-provider", "model": "my-custom-model", "config": {}, "plugin": "custom-plugin-key", "plugin_config": { "api_key": "MY-SECRET-KEY", "base_url": "my.custom.url" } } ], "id": 1 }' ``` # developers/intelligent-contracts/tools/genlayer-studio/contract-state.mdx # Current Intelligent Contract State Once your Intelligent Contract is deployed, you can check its current state to verify that it has been initialized correctly. This step ensures that the contract's data and variables are set as expected. ## Viewing the Current Intelligent Contract State After deploying your contract, you will now see: - **Contract Address:** This is used for interacting with your contract. - **Read Methods:** These return information on the current state of the contract. import Image from 'next/image' import { Callout } from 'nextra-theme-docs' Getter function names must start with `get_`. If you do not include a getter function in your code, it will not appear in this section. For example, in the **Storage** contract: - If the constructor parameter `initial_storage` was set to `hello`, the state method `get_storage` will return `hello`. The result will show the current state based on the getter function called. This allows you to verify that the variables in your contract have been initialized correctly and that they change when transactions are executed. When the contract state changes, you can always come back and refresh the state by calling these getter functions to see the most current state of your Intelligent Contract. With the state verified, you can now execute transactions and interact with your deployed contract. # developers/intelligent-contracts/tools/genlayer-studio/deploying-contract.mdx # Deploy Contracts Once you have loaded your Intelligent Contract into the GenLayer Studio, the next step is to set the constructor parameters and deploy it. The constructor parameters are essential inputs that initialize the state of your contract. ## Setting Constructor Parameters 1. After loading your Intelligent Contract, you will see the **Constructor Inputs** section on the left-hand pane. The constructor parameters are [automatically detected from your code if defined properly](#detecting-constructor-parameters). 2. If you need to manually adjust your constructor parameters, you can write them in JSON format by clicking on the **JSON** button. import Image from 'next/image' ## Detecting Constructor Parameters The GenLayer Studio automatically detects the constructor parameters from your code. It analyzes your `__init__` method to identify the parameters and their types. This automatic detection ensures that you have the correct inputs for initializing your contract. It’s important to have clear type annotations for each parameter (e.g., `str`, `bool`, `int`, `list`) to enable accurate detection. ## Deploying the Contract After setting the constructor parameters, click on **Deploy** to deploy your contract. Once completed, you can proceed to execute your transactions and interact with the deployed contract. # developers/intelligent-contracts/tools/genlayer-studio/development-tips.mdx import Image from 'next/image' # Development Tips Here are some valuable tips on how to develop your intelligent contract, debug it, and test it using the Genlayer Studio. ## 1. Validators setup You need to be sure that you have at least one validator. If you don't have any, you can create one in the validators screen by providing: - Provider - Model - Stake (at least 1) - Config (optional) ## 2. Add types to your contract method inputs Adding types to your contract method inputs helps the UI render the correct input fields. For example, if you have a method that takes a string as input, you can define it as follows: ```python def update_storage(self, new_storage:str) -> None: self.storage = new_storage ``` This will allow the UI to render the form needed to call the contract with the correct input type as follows
Node Log ## 3. The constructor The constructor is a special method called when the contract is deployed. It is used to initialize the contract's storage. You can define it as follows: ```python def __init__(self, initial_storage: str): self.storage = initial_storage ``` Right now, your contract must include a constructor. Without one, the Studio won't be able to deploy your contract. ## 4. Deploying a contract and sending transactions After you have written your contract, you can deploy it by clicking the "Deploy" button. This will deploy the contract and show you the contract's address.
You can then call the contract's methods, shown below in the deployment section on the left panel of the Studio's UI.
Node Log ## 5. Debugging your contract You can debug your contract by adding print statements to your contract methods. The Studio's Logs section will display these print statements. Here is an example of printing in a contract method: ```python def update_storage(self, new_storage:str) -> None: print("new storage value: ", new_storage) self.storage = new_storage ``` When a transaction is sent to this method, the print statement will be shown in the Logs section as follows:
Node Log ## 6. What happened when the transaction was executed After a transaction is executed, you can see the details by clicking on the transaction in the Transactions section (left-bottom corner). This will show you: - Number: The transaction's number in the database - Timestamp: The time the transaction was executed - Type: The transaction's type (deployment or method call) - Status: The transaction's status (PENDING, PROPOSING, COMMITTING, REVEALING, ACCEPTED, FINALIZED) - Input: the parameters passed to the method - Execution: The status of the execution (SUCCESS or ERROR), the leader's configuration, and the validator's consensus votes - Equivalence principle output: The output of the equivalence principle from the leader
Node Log ## 7. Knowing what happens when the LLMs are called If a contract method calls an LLM, you can see the Equivalence Principle Output from the leader (what's being input in the eq.set call) in the transaction details modal.
Node Log ## 8. Access to the contract state If your contract methods change the contract's state, you can query that information by adding a read method to your contract. Read methods on a contract need to be decorated with the `@gl.public.view` decorator. This method should return the state you want to query.
For example: ```python @gl.public.view def get_balances(self) -> dict[str, int]: return self.balances @gl.public.view def get_balance_of(self, address: str) -> int: return self.balances.get(address, 0) ``` These two methods allow you to query the contract's balance state. You can call them by expanding them from the left panel of the Studio's UI and clicking on the "Call Contract" button. # developers/intelligent-contracts/tools/genlayer-studio/execute-transaction.mdx # Execute Transactions After deploying your Intelligent Contract and verifying its state, the next step is to execute transactions. This allows you to interact with your contract's methods and functions to perform specific actions or queries. ## Write Methods 1. In the **Write Methods** section, you will see all the write methods available in your Intelligent Contract. 2. Expand the method you want to execute. For example, in the **Storage** contract, select the `update_storage` method. 3. If the method requires input parameters, a field will appear for you to enter the necessary values. For example, the `update_storage` method requires a string called `new_storage`. import Image from 'next/image' Deploy Contract 4. After entering any required parameters, click the button to execute the method. The Studio will process the transaction and return the result. ## Viewing Transaction Results Once you execute a transaction, the result will be displayed, showing the output of the method called. This allows you to verify that the method has executed correctly and to see the effect of the transaction on your contract's state. ## Viewing Current Account Address You can also view your current account address in the header. This address is used to interact with your contract. Select Active Account You can continue interacting with your Intelligent Contract by executing additional transactions or checking the state again to see how it has changed. # developers/intelligent-contracts/tools/genlayer-studio/limitations.mdx # Limitations of the GenLayer Studio The GenLayer Studio is in an early stage of development, with many features still being tested and refined. Here are some limitations of the studio: ## Native Token Transfers Native Token transfers to and from contracts are not supported in the Studio. ## Gas Usage Transactions within the Studio do not consume gas. While this is beneficial for rapid prototyping, the absence of gas simulation may result in behavior differing from live blockchain networks. ## Consensus Algorithm The GenLayer Studio does not implement the full Optimistic Democracy consensus mechanism. There is no appeals process. The studio focuses on providing a basic execution environment without the complexities of the full consensus mechanism. ## Programming Language The programming language used in the Studio is an early version and is not final. It is expected to undergo many changes as development progresses. ## Web Access While the Studio supports web browsing capabilities, it is primarily for testing purposes. The actual web access and data retrieval might differ when deployed on the live network. # developers/intelligent-contracts/tools/genlayer-studio/loading-contract.mdx # Load Your Contract To start using the GenLayer Studio, you need to load your Intelligent Contract into the Studio. This involves navigating the Studio interface, selecting your contract file, and preparing it for deployment and execution. ## Access your Intelligent Contracts 1. On the left sidebar, click on the **Contracts** icon. This is where you can see the list of your Intelligent Contracts. There are pre-loaded example contracts for you to try out. import Image from 'next/image' Navigate Contract 2. To add a new contract, click on the **+** button labeled **New Contract** to create a new contract file in the Studio. Add a New Contract 3. Click on the **Add From File** button to select and upload your Intelligent Contract file from your local machine. Add From File 4. Once your contract is uploaded, you will see it listed under **Your Contracts**. ## Run Your Intelligent Contract 1. Click on the contract file to open it in the editor pane. This allows you to review and edit the code if necessary before running it. Open the Contract 2. Once you have your contract file open, you have two options to run and debug your contract: - Click the **Run and Debug** button on the left sidebar. - Click the **play icon** at the top right of the editor pane. Run and Debug Now that you have loaded your Intelligent Contract into the GenLayer Studio, you can proceed to set constructor parameters and deploy it. # developers/intelligent-contracts/tools/genlayer-studio/monitoring-node-logs.mdx # Monitoring Node Logs Node Logs in the GenLayer Studio provide real-time feedback and are a critical component for debugging and tracking the behavior of Intelligent Contracts as they interact within the studio. ## Key Features of Node Logs Node Logs capture and display a variety of events, including: - **Transaction Submission, Status Changes and Finalization:** Track the status and outcomes of submitted transactions. - **Contract Deployment Statuses:** Monitor the progress and success of contract deployments. - **Execution Results and Errors:** Review the outputs and any errors encountered during contract execution. - **Validator Operations and Consensus-Related Messages:** Observe the activities of validators and consensus processes. ## Accessing Node Logs You can view the node logs at the bottom of the GenLayer Studio. This section automatically updates with new log entries as actions are performed within the studio. You can also filter the logs by content as well as by scope and level. ![Node Log](/node-logs.png) ## Understanding Node Logs The logs are structured to provide clear and detailed information: - **Scope:** Each log is tagged with a label such as RPC or GenVM to give you a better understading of the context of the log. - **Level:** Log entries are associated with a level and color to facilitate rapid scanning for issues or confirmations. - **Details:** Expandable log entries offer detailed explanations and data for each event, such as transaction hashes or error messages. By actively viewing these logs, you can ensure that your Intelligent Contracts are performing as expected and that any issues are promptly addressed. This leads to a smoother development process within the GenLayer Studio. # developers/intelligent-contracts/tools/genlayer-studio/providers.mdx import Image from 'next/image' # Inference Providers Validators can use various inference providers to validate transactions. You can configure those providers and add custom ones to suit your needs. When you then create a new validator in the validators page, you will be able to select those providers and the relevant models from the list. ## Accessing Providers You can manage your providers in the **Settings** page: ## Configuring Providers Providers have the following properties: - **Provider:** The name of the provider. For example, `OpenAI` or `ollama`. - **Model:** The model attached to this provider. For example, `gpt-4o` or `llama3`. - **Plugin: (only for custom providers)** When adding a custom provider, you need to specify a plugin that implements the provider. The plugin defines what configuration is necessary for the provider. - **Provider Config:** Related environment variables, for example API keys or endpoint URLs. - **Default Validator Config:** This config is used as fefault when creating a new validator, and will then be applied when making calls to inference providers using said validator. ## Adding a new Provider You can add a new provider by clicking the **New Config** button at the top of the providers list. ## Updating an Existing Provider To modify your validator settings, click on any existing validator and modify the fields based on your needs. ## Deleting a Provider To delete a provider, click on the delete button beside the provider in the list. # developers/intelligent-contracts/tools/genlayer-studio/reset-the-studio.mdx import Image from 'next/image' # Resetting the GenLayer Studio The GenLayer Studio provides a straightforward way to reset its storage, current status, memory, and contract examples. This feature is particularly useful if you want to start fresh with a clean state, whether you’re testing new contracts or simply clearing out previous configurations. ## How to Reset the Studio To reset the GenLayer Studio, follow these simple steps: 1. **Access the Settings Page**: begin by navigating to the Settings page within the GenLayer Studio. 2. **Click "Reset Storage"**: this option allows you to clear all the current data stored in the studio, including the state of deployed contracts, transaction history, and any cached information. 3. **Confirm the Reset in the Dialog**: this is an important step, as resetting the storage will remove all existing data and cannot be undone. Once confirmed, the studio will reset its storage, returning to its initial state as if it were newly initialized. ## What Does Resetting Do? Resetting the GenLayer Studio through the Reset Storage option will: - Clear All Deployed Contracts: Any contracts that you have deployed in the studio will be removed from the frontend memory. - Reset Transaction History: All previous transactions, including those in various states, will be erased. - Restore Contract Examples: Any example contracts included in the studio will be restored to their original, unaltered state. ## When Should You Reset? Consider resetting the studio when: - You want to start with a clean slate for a new development or testing session. - You encounter issues that might be caused by lingering data or state inconsistencies. - You have completed a testing phase and need to ensure that previous data does not interfere with new experiments. # developers/intelligent-contracts/tools/genlayer-studio/troubleshooting.mdx # Troubleshooting If you encounter any issues with the Studio, here are some detailed steps to help you resolve common problems: ## Frontend Not Loading Correctly The frontend may not load correctly due to caching issues or an outdated version of the contract stored in your browser. ### Solution - **Refresh Frontend:** Simply reload the page in your browser. - **Clear Cache:** Clear your browser's cache by clicking on the left of your address bar -> Cookies and site data -> Manage on device site data -> Delete localhost. import Image from 'next/image' Node Log ## Port Conflicts The Studio may fail to start if some ports required for its operation are already in use by other applications. **Ports used by the Studio:** - **Frontend:** 8080 - **Ollama:** 11434 - **JSON-RPC Server:** 4000 - **GenVM:** 6678 ### Solution 1. Identify processes using the required ports. Replace `` with the specific port number. - **Linux / MacOS:** ```bash copy lsof -i : ``` - **Windows:** ```cmd copy netstat -aon | find ``` 2. Use the following command to kill the process using the port. Replace `` with the Process ID obtained from the previous step. - **Linux / MacOS:** ```bash copy kill -9 ``` - **Windows:** ```cmd copy taskkill /PID /F ``` ## Docker not Running The Genlayer Studio relies on Docker for managing containers and images. If Docker is not running, the Studio cannot function properly. ### Solution - Ensure that Docker (or Docker Desktop) is installed on your system. You can check this by running: ```bash copy docker info ``` - Restart Docker Desktop or the Docker daemon on your system. ## Display Issues The code section or other UI elements may not display correctly due to screen size limitations. ### Solution - Resize your screen to accommodate the UI elements properly. This will help improve the visibility and layout of the Studio. ## Studio Not Responding or Throwing Errors The Studio may become unresponsive or throw errors due to various reasons, such as conflicting processes or corrupted containers. ### Solution You can perform a fresh start by stopping and removing all containers, as well as removing all images. **Via Command Line:** ```bash docker stop $(docker ps -aq) docker rm $(docker ps -aq) docker rmi $(docker images -q) ``` **Via Docker Desktop:** 1. Open Docker Desktop and go to the **Containers** section. 3. Select all containers and click **Delete**. 4. Go to the **Images** section. 5. Select all images and click **Delete**. # developers/intelligent-contracts/tools/genlayer-studio/validators.mdx import Image from 'next/image' # Accessing and Configuring Validators In the GenLayer Studio, validators are essential for achieving consensus and validating transactions through a process known as [Optimistic Democracy](/core-concepts/optimistic-democracy). When you initialize the Studio based on your selected LLM provider(s), you are provided with 5 default validators. 1. **Leaders:** Within this consensus model, one validator is selected as the leader for each transaction. The leader's role is to propose how a transaction should be executed based on the transaction data and the Intelligent Contract's logic. 2. **Validators:** After the leader proposes a transaction execution, other validators are responsible for reviewing and validating the proposal. They use the [Equivalence Principle](/core-concepts/optimistic-democracy/equivalence-principle) to determine if the leader’s proposal meets the required standards. These validators can be modified to suit your Intelligent Contract's requirements. ## Accessing Validators To access and manage validators, follow these steps: 1. On the left sidebar, click on the **Validators** icon. This will open the validators page. 2. In the validators page, you will see a list with all the validators currently configured in the Studio along with their models and providers. ## Configuring Validators To configure validators, you can add new validators or modify existing ones. 1. Click the **New Validator** button to open the validator creation dialog. 2. **Create New Validator:** In the validator creation dialog, fill in the required fields: - **Provider:** Select the provider for the validator. - **Model:** Choose the model that the validator will use. - **Stake:** Specify the stake for the validator. - **Config:** Enter any additional configuration parameters in JSON format. 3. Click **Create** to add the new validator to your configuration. ## Modify Validator Details To modify your validator settings, click on any existing validator and modify the fields based on your needs. ## Delete Validator To delete a validator, click on the delete button beside the validator in the list. By properly managing and configuring validators, you ensure that your Intelligent Contracts operate smoothly and securely within the GenLayer Studio. # developers/intelligent-contracts/tools/genlayer-studio.mdx import { Card, Cards, Callout, Bleed } from 'nextra-theme-docs' # GenLayer Studio This Studio is an interactive sandbox designed for developers to explore the potential of GenLayer's Intelligent Contracts. It replicates the GenLayer network's execution environment and consensus algorithm, but offers a controlled and local environment to test different ideas and behaviors. ### What you can do with the GenLayer Studio: - **Experiment with AI smart contracts:** Intelligent Contracts leverage LLMs, such as GPT-4 or Llama3, to understand natural language and be capable of complex decision making. - **Access the Web Natively:** Genlayer is the first platform where smart contracts don’t need oracles to access the internet. - **Code in Python:** Develop in a familiar, developer-friendly language, where memory and string management are not a big headache. ### Explore the Studio Here is a video introduction to help you get started with the GenLayer Studio:
### Intelligent Contract SDK Learn how to write your own Intelligent Contracts at [Intelligent Contracts](/build-with-genlayer/intelligent-contracts) # developers/intelligent-contracts/types.mdx # Types in Intelligent Contracts GenVM provides type support for both contract development (storage/state variables) and contract interaction (calldata). Understanding these types is crucial for developing robust Intelligent Contracts. ## Contract Development Types When writing Intelligent Contracts, you can use the following types for state variables and method parameters: ### Primitive Types - **Integers** - `u8`, `u16`, `u32`, `u64`, `u128`, `u256` - Unsigned integers of various sizes - `i8`, `i16`, `i32`, `i64`, `i128`, `i256` - Signed integers of various sizes - `bigint` - Arbitrary precision integer (use with caution, prefer sized integers) - **Other Primitives** - `bool` - Boolean values (True/False) - `str` - UTF-8 encoded string - `bytes` - Raw byte sequences - `Address` - Blockchain address (20 bytes) ### Collection Types - **Arrays** - `DynArray[T]` - Dynamic array of type T (replaces Python's `list[T]`) - **Maps** - `TreeMap[K, V]` - Ordered map from key type K to value type V (replaces Python's `dict[K, V]`) ### Custom Types You can use custom Python classes in storage, for example: ```python @dataclass class User: name: str balance: u256 @gl.contract class Contract: users: DynArray[User] ``` ## Calldata Types When interacting with contract methods, the following types are supported: - **Basic Types** - Integers (converted to appropriate sized type) - Strings - Bytes - Booleans - `None` - Address (as hex string with '0x' prefix) - **Collections** - Lists (converted to `DynArray`) - Dictionaries (must have string keys, converted to `TreeMap`) ## Type Restrictions and Best Practices ### Storage Type Restrictions 1. **No Raw Python Collections** - Use `DynArray[T]` instead of `list[T]` - Use `TreeMap[K, V]` instead of `dict[K, V]` 2. **No Raw Integers** - Use sized integers (`u256`, `i64`, etc.) instead of `int` - Use `bigint` only when absolutely necessary 3. **Generic Types Must Be Fully Specified** ```python # ❌ Wrong storage: TreeMap # Not fully specified # ✅ Correct storage: TreeMap[str, u256] # Fully specified ``` ### Type Conversion in Calldata When calling contract methods: - String keys are required for dictionary parameters - Numbers are automatically converted to appropriate sized integers - Addresses should be provided as hex strings with '0x' prefix # developers.mdx import CustomCard from '../components/card' # Getting Started with GenLayer Welcome to the GenLayer getting started guide. This guide will help you set up the GenLayer environment, write your first Intelligent Contract, deploy it, and interact with it using the GenLayer Studio. You'll also learn how to use the Genlayer Project Boilerplate to write end-to-end tests and build a frontend dApp with GenLayerJS. ## Table of Contents 1. [Using the GenLayer Studio](#using-the-genlayer-studio) 2. [Installation of the GenLayer CLI](#installation-of-the-genlayer-cli) 3. [Launching the GenLayer Simulator](#launching-the-genlayer-simulator) 4. [Writing Intelligent Contracts](#writing-intelligent-contracts) 5. [Deploying and Interacting with Intelligent Contracts](#deploying-and-interacting-with-intelligent-contracts) 6. [Writing End-to-End Tests with genlayer-project-boilerplate](#writing-end-to-end-tests-with-genlayer-project-boilerplate) 7. [Building a Frontend dApp with GenLayerJS](#building-a-frontend-dapp-with-genlayerjs) ## Using the GenLayer Studio The GenLayer Studio is a web-based interface for developing, testing, and deploying Intelligent Contracts. It provides a user-friendly environment for interacting with the GenLayer ecosystem. You can find it at [studio.genlayer.com](https://studio.genlayer.com). ## Local Installation of the GenLayer CLI The GenLayer CLI is used to set up the GenLayer Studio and, in the future, mainnet and testnet environments. ### Prerequisites Ensure you have the following installed and updated:
### Installation Steps 1. **Install GenLayer CLI** Open your terminal and run: ```bash npm install -g genlayer ``` 2. **Initialize GenLayer Environment** Run the following command to set up your development environment: ```bash genlayer init ``` During initialization, you'll be prompted to select your preferred LLM provider(s) and enter any required API keys. **Optional Initialization Parameters** You can customize the initialization with the following options: - `--numValidators `: Specify the number of validators (default is 5). - `--branch `: Specify the branch of the GenLayer Studio to use (default is "main"). Example: ```bash genlayer init --numValidators 3 --branch staging ``` ## Launching the GenLayer Studio After initializing the environment, you can start the Studio by running: ```bash genlayer up ``` This command launches the GenLayer Studio using your existing configuration. **Optional Parameters:** - `--reset-validators`: Removes all current validators and creates new ones. - `--numValidators `: Specify the number of validators to start. - `--branch `: Specify the branch to start the GenLayer Studio from. Example: ```bash genlayer up --reset-validators --numValidators 3 --branch staging ``` Once the Studio is running, access it at http://localhost:8080/. ## Writing Intelligent Contracts Refer to the [Intelligent Contracts](./build-with-genlayer/intelligent-contracts/first-contract) page for more information on how to write Intelligent Contracts. ## Deploying and Interacting with Intelligent Contracts ### Deploying the Contract 1. **Load Your Contract**
In the GenLayer Studio, navigate to the Contracts section and upload your contract file. 2. **Set Constructor Parameters**
The Studio will automatically detect constructor parameters. Provide the required values. 3. **Deploy the Contract**
Navigate to the Run and Deploy section and click the "Deploy" button. Upon successful deployment, the contract address will be displayed. ### Interacting with the Contract 1. **Read Methods**
View the current state of the contract using Read Methods. These are methods that return data without modifying the state. 2. **Write Methods**
Execute Write Methods to interact with your contract. Provide any required input parameters. 3. **Transaction Logs**
Monitor transactions and validator consensus via the Node Logs at the bottom of the Studio. ## Writing End-to-End Tests with genlayer-project-boilerplate The [genlayer-project-boilerplate](https://github.com/yeagerai/genlayer-project-boilerplate/) provides a starting point for writing end-to-end (e2e) tests for your Intelligent Contracts. ### Setting Up the Boilerplate 1. **Clone the Repository** On a location different from the GenLayer Studio, clone the repository: ```bash git clone https://github.com/yeagerai/genlayer-project-boilerplate.git ``` 2. **Install Dependencies**
Navigate to the project directory and install the required packages: ```bash cd genlayer-project-boilerplate npm install ``` 3. **Configure Environment**
Ensure the GenLayer Studio is running. Update the configuration files if necessary. ### Writing E2E Tests 1. **Create Test Files**
In the `test` directory, create test files using your pytest as a testing framework. 2. **Example Test** ```python import pytest from genlayer import GenLayer, Account def test_simple_contract(): # Account account_1 = create_new_account() # Deploy contract contract_code = open("contracts/my_contract.py", "r").read() contract_address, transaction_response_deploy = deploy_intelligent_contract( account_1, contract_code, "{value = 10}", ) # Test initial state initial_value = call_contract_method( contract_address, account_1, "get_value", [] ) assert initial_value == 10 # Test state change send_transaction_response = send_transaction( account_1, contract_address, "set_value", ["20"], ) # Test updated state updated_value = call_contract_method( contract_address, account_1, "get_value", [] ) assert updated_value == 20 ``` **Note on Deployment**: For deployment, developers should currently use the GenLayer Studio UI. Deploying through the CLI is not yet supported. ## Building a Frontend dApp with GenLayerJS You can build a frontend decentralized application (dApp) that interacts with your Intelligent Contract using GenLayerJS, a JavaScript SDK for GenLayer. You can start by cloning the [genlayer-dapp-boilerplate](https://github.com/yeagerai/genlayer-dapp-boilerplate/) repository or start from scratch with a new frontend project. After you have your project ready, continue with the following steps: ### Installing GenLayerJS ```bash npm install genlayer-js ``` ### Connecting to GenLayer ```javascript import { createClient } from 'genlayer-js'; const client = createClient(config); ``` ### Interacting with Contracts 1. **Read from a Contract** ```javascript const value = await client.readContract({ address: contractAddress, functionName: "get_value", args: [], }); ``` 2. **Update Contract State** ```javascript const txHash = await client.writeContract({ address: contractAddress, functionName: "set_value", args: [newValue], }); const receipt = await client.waitForTransactionReceipt({ hash: txHash, status: "FINALIZED", }); ``` ### Running the Frontend Ensure your frontend application is configured to connect to the GenLayer Studio's RPC endpoint (http://localhost:4000/api). Start your frontend application: ```bash npm run dev ``` ## Conclusion You've now set up the GenLayer environment, written and deployed an Intelligent Contract, and interacted with it through both the Studio and a frontend dApp using GenLayerJS. Explore further by customizing your contracts, writing more comprehensive tests, and enhancing your dApp's functionality. # index.mdx import { Card, Cards } from 'nextra-theme-docs' import CustomCard from '../components/card' # Welcome to GenLayer Docs GenLayer is a decentralized blockchain platform designed to execute AI-powered smart contracts called **Intelligent Contracts** which can use AI models to search the web and process natural language instructions. To navigate the docs, the sidebar on the left organizes the documentation, one can start with knowing generic concepts [about the GenLayer Protocol](/about-genlayer), and then choosing a path as a [Developer](/developers). ## Find your way in the docs
{/* */} {/* */}
## Partners We feature various collaborators who help drive our innovation. YeagerAI Heurist ## Questions? Join the GenLayer community in our [Discord](https://discord.gg/8Jm4v89VAu) and [Telegram](https://t.me/genlayer) to ask for help, as well as share your feedback or showcase what you have built with GenLayer! ## Join us We are hiring! If you are passionate about blockchain technology and want to be part of an innovative team, check out our [career opportunities](https://apply.workable.com/yeager-dot-a-i/) and join us in shaping the future of decentralized applications. # partners/heurist.mdx # Heurist [Heurist](https://www.heurist.ai/) is a Layer 2 network for AI model hosting and inference, built on the ZK Stack. It offers serverless access to open-source AI models through a decentralized network, making AI deployment easy and efficient for developers. This approach promotes transparency and reduces bias, which is especially useful for projects like GenLayer that require detailed AI analysis. In collaboration with GenLayer, Heurist provides APIs for open-source large language models (LLMs) to enable developers building Intelligent Contracts use AI at low or no cost. Developers building on GenLayer can obtain free [Heurist API credits](https://dev-api-form.heurist.ai) by using the referral code: _"genlayer"_. This partnership underscores our commitment to providing robust tools and scalable solutions for decentralized applications. # partners/yeager.mdx ## Yeager AI [YeagerAI](https://www.yeager.ai/) is a pioneering AI research lab dedicated to revolutionizing human-AI interaction. They are one of the core developers of GenLayer, focusing on using AI to enhance the performance, security, and scalability of blockchain networks. By embedding AI into the blockchain’s core, YeagerAI enables decentralized applications to make smart decisions autonomously, opening new possibilities for automation and efficiency in various industries. We encourage other developers and organizations to collaborate with YeagerAI on this groundbreaking project. Together, we can push the boundaries of what AI and blockchain technology can achieve. # validators.mdx import { Callout } from 'nextra-theme-docs' # GenLayer Validator Hardware Requirements Running a GenLayer Validator node ensures the security and reliability of the GenLayer network. Below are the **initial** recommended hardware requirements. These guidelines may change as the network grows and evolves. ## RAM - **Recommended:** 16 GB - **Why:** - GenLayer's _genvm_ can spawn multiple Sub-VMs for contract calls and non-deterministic blocks. - Each Sub-VM can consume up to ~4 GB of RAM for storage. ## CPU - **Recommended:** Modern multi-core processor with at least 8 cores/16 threads ## Storage - **Recommended Disk Space:** 128 GB+ - **Preferred Type:** SSD or NVMe (M.2) ## GPU (Optional) - **Recommended:** If you plan to run advanced AI-models locally, a CUDA-compatible GPU could be beneficial. ## Network - **Recommended Connection:** Stable broadband ## Operating System - **Recommended:** 64-bit Linux (Ubuntu, Debian, CentOS, etc.) These requirements are a starting point. As GenLayer evolves and usage patterns change (e.g., more complex AI-driven Intelligent Contracts), the recommended hardware may change.