GLIP

GLIP stands for Glittr Improvement Proposals. There are # standards that are already implemented by the core team and more improvement can be proposed by anyone via GitHub.

Core Standards

The core standards cover mostly the digital assets that can be deployed within the Glittr Ecosystem. Currently only Asset Contracts are implemented by the core team.

  1. Asset Contracts

    1. Simple Asset

      1. Free Mint

      2. Preallocated

      3. Purchase/Burn

Develop New GLIP

For more customized and a lot more complex logic there might be a need to develop a new GLIP. To develop a GLIP, you need to run your own localnode and write a new code that will be validate & process the new transaction based on your own specification. During development you can use the ./watch.sh to automatically cargo check and cargo test your code.

Prerequisites:

Run Localnet

Guides:

NOTE: If you prefer to learn from example, you can look into the `GLIP-1: Governance Contract` example.

To create a new GLIP standard, you need to write the new custom logic with RUST into the glittr-core's code. Most of your changes will be inside /src/transaction

Inside /src/transaction/message.rs add new enum entry to

  1. ContractType (if you want to add new contract)

  2. CallType (if you want to add new call to your contract, or existing contract)

message.rs
#[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ContractType {
    Asset(AssetContract),
    Custom(CustomContract), // new contract
}

#[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum CallType {
    Mint(MintOption),
    Burn,
    Swap,
    // new calls only for the new conctract contract
    CreateProposal(ProposalCreation), 
    Vote(Vote),
    ExecuteProposal(BlockTxTuple),
    VetoProposal(BlockTxTuple),
}

Of course, you need to implement the new ContractType or CallType that you declare. Create a new file under /src/transaction, let's call it custom_contract.rs. This is where all of your OP_RETURN structure is being written. Since we are using rust and serialize it to JSON (for devnet), we are using serde_json for convenience, don't fret about the serialization. Your contract structure will be using Rust's struct, also you need to implement static validate(&self) here to validate your contract creation values.

custom_contract.rs
use super::*;

#[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub struct CustomContract {
    pub governance_token: BlockTxTuple,
}

...

impl CustomContract {
    pub fn validate(&self) -> Option<Flaw> {
        // Validate governance token exists
        if self.governance_token.1 == 0 {
            return Some(Flaw::InvalidBlockTxPointer);
        }
    }
}

If you have validation that is dependent on the runtime (block height, checking if the token really exist, etc), you must edit the index function inside src/updater.rs.

updater.rs
            if let Some(contract_creation) = message.contract_creation {
                if let ContractType::Asset(asset_contract) = contract_creation.contract_type {
                   ... // do validation here
                    }
                }
            }

In the same file, you can also implement the logic for all your CallTypes.

updater.rs
            if let Some(contract_call) = message.contract_call {
                match contract_call.call_type {
                    // Implement your call types here
                    CallType::CreateProposal(_) => todo!(),
                    CallType::Vote(_) => todo!(),
                    CallType::ExecuteProposal(_) => todo!(),
                    CallType::VetoProposal(_) => todo!(),
                }

Make sure you add tests and the previous tests still work as well.


Typescript Library

For every change in the Glittr Core code, we should update the SDK to match the new message format. Example: https://github.com/Glittrfi/glittr-sdk-public/pull/1

  1. ContractType (If you want to add a new ContractType message, you should create a new file in /packages/sdk/src/transaction/contract/<new_contract_creation>.ts) .e.g

custom.ts
import { BlockTxTuple, PubKey } from "../../utils";

export type CustomContract = {
  custom_token: BlockTxTuple;
  custom_owner: Pubkey;
  // add more here
};
  1. CallType (to add new CallType, you should create new file in /packages/sdk/src/transaction/callType/<new_call_type>.ts)

custom.ts
import { BlockTxTuple } from "../../utils";

export type CustomCall = {
  title: string;
  description: string;
};

export type CustomVote = {
  proposal_id: BlockTxTuple;
};

After creating a new file in /packages/sdk/src/transaction/contract/ (for new contract creation) and in /packages/sdk/src/transaction/callType/(for new calltype), we should add new type definition for contract creation in packages/sdk/src/transaction/contract/types.ts

types.ts
import { AssetContract } from "./asset";
import { CustomContract } from "./custom";

export type ContractType = {
  asset?: AssetContract;
  custom?: CustomContract // new contract
};

And also add new type definition for call type in packages/sdk/src/transaction/calltype/types.ts

types.ts
import { CustomCall, CustomVote } from "./governance";

...

export type CallType =
  | { mint: MintOption }
  | { burn: {} }
  | { swap: {} }
  | { custom_call: CustomCall } // new call type
  | { custom_vote: CustomVote }; // new call type

After completing those steps, we can add a new function and message definition for txBuilder. Edit the file in packages/sdk/src/transaction/message.ts

message.ts
import { CustomContract } from "./contract/custom"; // add new import line

...

// add new message format and necessary function params for txBuilder 
export type CustomContractInstantiateFormat = {
  contract_creation: {
    contract_type: {
      custom: CustomContract
    }
  } 
}
export type CustomContractParams = {
  custom: CustomContract
}

export type TransactionFormat =
  | MintContractCallFormat
  | TransferFormat
  | PreallocatedContractFormat
  | PurchaseBurnContractFormat
  | FreeMintContractInstantiateFormat
  | CustomContractInstantiateFormat; // new transaction format

Now create the function for the txBuilder in packages/sdk/src/transaction/index.ts

index.ts
// Some code
import { CustomContractInstantiateFormat, CustomContractParams } from "./message"

...

// new function here
static customContractInstantiate(
  params: CustomContractParams
): CustomContractInstantiateFormat {
  return {
    contract_creation: {
      contract_type: {
        custom: params.custom,
      },
    },
  };
}
  
...
  

PR Format

For Encode hackathon participant, please make a PR to https://github.com/Glittrfi/glittr-core-public and https://github.com/Glittrfi/glittr-core-public.

# Overview
This PR introduces ...

# Key Features
- Build an awesome contract
...

# Technical Changes 
- Add awesome contract structure
...

# Testing
- Add unit tests for contract validation

# Documentation
- Add inline documentation for functions
- Update README with governance features
- Add examples for creating and interacting with the awesome contract

# Future Improvements
- Add support for ...
- Implement timelock functionality for sensitive actions
- Add ...
- Consider implementing ...

# Breaking Changes
None. This is an additive change that maintains compatibility with existing contracts.

# Security Considerations
- Validated all pubkeys ...
- Implemented checks for ...
- Added safeguards against invalid configurations
- Ensured proper validation of execution permissions

# Related Issues
Closes #XXX (Add issue number if applicable)

Example

We have prepared a GLIP example, in this example we are creating a Governance Contract* : https://github.com/Glittrfi/glittr-core-public/pull/1 * this example is not complete, but you should provide a finished implementation with tests

Last updated