Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CRISP/sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
// or FITNESS FOR A PARTICULAR PURPOSE.

export const CRISP_SERVER_TOKEN_TREE_ENDPOINT = 'state/token-holders'
export const CRISP_SERVER_STATE_LITE_ENDPOINT = 'state/lite'
7 changes: 5 additions & 2 deletions examples/CRISP/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

export * from "./token";
export * from "./constants";
export * from './token'
export * from './state'
export * from './constants'

export type { IRoundDetails, ITokenDetails } from './types'
55 changes: 55 additions & 0 deletions examples/CRISP/sdk/src/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: LGPL-3.0-only
//
// This file is provided WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

import { CRISP_SERVER_STATE_LITE_ENDPOINT } from './constants'

import type { IRoundDetailsResponse, IRoundDetails, ITokenDetails } from './types'

/**
* Get the details of a specific round
*/
export const getRoundDetails = async (serverUrl: string, e3Id: number): Promise<IRoundDetails> => {
const response = await fetch(`${serverUrl}/${CRISP_SERVER_STATE_LITE_ENDPOINT}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ round_id: e3Id }),
})

const data = (await response.json()) as IRoundDetailsResponse

return {
e3Id: BigInt(data.id),
tokenAddress: data.token_address,
balanceThreshold: BigInt(data.balance_threshold),
chainId: BigInt(data.chain_id),
enclaveAddress: data.enclave_address,
status: data.status,
voteCount: BigInt(data.vote_count),
startTime: BigInt(data.start_time),
duration: BigInt(data.duration),
expiration: BigInt(data.expiration),
startBlock: BigInt(data.start_block),
committeePublicKey: data.committee_public_key,
emojis: data.emojis,
}
}
Comment thread
ctrlc03 marked this conversation as resolved.

/**
* Get the token address, balance threshold and snapshot block for a specific round
* @param serverUrl - The base URL of the CRISP server
* @param e3Id - The e3Id of the round
* @returns The token address, balance threshold and snapshot block
*/
export const getRoundTokenDetails = async (serverUrl: string, e3Id: number): Promise<ITokenDetails> => {
const roundDetails = await getRoundDetails(serverUrl, e3Id)
return {
tokenAddress: roundDetails.tokenAddress,
threshold: roundDetails.balanceThreshold,
snapshotBlock: roundDetails.startBlock,
}
}
36 changes: 9 additions & 27 deletions examples/CRISP/sdk/src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,17 @@ import { CRISP_SERVER_TOKEN_TREE_ENDPOINT } from './constants'
* @param e3Id - The e3Id of the round
*/
export const getTreeData = async (serverUrl: string, e3Id: number) => {
try {
const response = await fetch(`${serverUrl}/${CRISP_SERVER_TOKEN_TREE_ENDPOINT}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ round_id: e3Id }),
})
const response = await fetch(`${serverUrl}/${CRISP_SERVER_TOKEN_TREE_ENDPOINT}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ round_id: e3Id }),
})

const hashes = await response.json()
const hashes = await response.json()

return hashes
} catch (error) {
console.error('Error fetching tree data:', error)
}
return hashes
}
Comment thread
ctrlc03 marked this conversation as resolved.

/**
Expand All @@ -38,17 +34,3 @@ export const generateMerkleProof = () => {}
* Get the token balance at a specific block for a given address
*/
export const getBalanceAt = () => {}

/**
* Interface representing the details of a specific round
*/
export interface IRoundDetails {
tokenAddress: string
snapshotBlock: string
threshold: string
}

/**
* Get the details of a specific round
*/
export const getRoundDetails = () => {}
52 changes: 52 additions & 0 deletions examples/CRISP/sdk/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: LGPL-3.0-only
//
// This file is provided WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

/**
* Interface representing the details of a specific round returned by the CRISP server
*/
export interface IRoundDetailsResponse {
id: string
chain_id: string
enclave_address: string
status: string
vote_count: string
start_time: string
duration: string
expiration: string
start_block: string
committee_public_key: string[]
emojis: [string, string]
token_address: string
balance_threshold: string
}

/**
* Interface representing the details of a specific round in a more convenient format
*/
export interface IRoundDetails {
e3Id: bigint
chainId: bigint
enclaveAddress: string
status: string
voteCount: bigint
startTime: bigint
duration: bigint
expiration: bigint
startBlock: bigint
committeePublicKey: string[]
emojis: [string, string]
tokenAddress: string
balanceThreshold: bigint
}

/**
* Interface representing the token details required for participation in a round
*/
export interface ITokenDetails {
tokenAddress: string
threshold: bigint
snapshotBlock: bigint
}
7 changes: 7 additions & 0 deletions examples/CRISP/sdk/tests/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: LGPL-3.0-only
//
// This file is provided WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

export const CRISP_SERVER_URL = 'http://localhost:4000'
29 changes: 29 additions & 0 deletions examples/CRISP/sdk/tests/state.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: LGPL-3.0-only
//
// This file is provided WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

import { describe, expect, it } from 'vitest'

import { getRoundDetails, getRoundTokenDetails } from '../src/state'
import { CRISP_SERVER_URL } from './constants'
import { zeroAddress } from 'viem'

describe('State', () => {
describe('getRoundDetails', () => {
it('should get the state for a given e3Id from the CRISP server', async () => {
const state = await getRoundDetails(CRISP_SERVER_URL, 0)
expect(state).toBeDefined()
})
})

describe('getTokenDetails', () => {
it('should return the details of the token for a given e3Id from the CRISP server', async () => {
const tokenDetails = await getRoundTokenDetails(CRISP_SERVER_URL, 0)
expect(tokenDetails.tokenAddress).not.toBe(zeroAddress)
expect(tokenDetails.threshold).toBeGreaterThan(0)
expect(tokenDetails.snapshotBlock).toBeGreaterThan(0)
})
})
})
4 changes: 2 additions & 2 deletions examples/CRISP/sdk/tests/token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
import { describe, expect, it } from 'vitest'

import { getTreeData } from '../src/token'
import { CRISP_SERVER_URL } from './constants'

// @notice To run these tests you will need to have an instance of CRISP running locally
describe('Token data fetching', () => {
const serverUrl = 'http://localhost:4000'
it('should fetch token data from the CRISP server', async () => {
const data = await getTreeData(serverUrl, 0)
const data = await getTreeData(CRISP_SERVER_URL, 0)
expect(data.length).toBeGreaterThan(0)
})
})
13 changes: 7 additions & 6 deletions examples/CRISP/server/src/server/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ pub async fn register_e3_requested(
info!("E3Requested: {:?}", event);

async move {
repo.initialize_round().await?;

// Convert custom params bytes back to token address and balance threshold.
let custom_params: CustomParams =
serde_json::from_slice(&event.e3.customParams)
.with_context(|| "Failed to parse custom params from E3 event")?;
// Convert custom params bytes back to token address and balance threshold.
let custom_params: CustomParams =
serde_json::from_slice(&event.e3.customParams)
.with_context(|| "Failed to parse custom params from E3 event")?;

let token_address: Address = custom_params
.token_address
Expand All @@ -63,6 +61,9 @@ pub async fn register_e3_requested(
BigUint::parse_bytes(custom_params.balance_threshold.as_bytes(), 10)
.ok_or_else(|| eyre::eyre!("Invalid balance threshold"))?;

// save the e3 details
repo.initialize_round(custom_params.token_address, custom_params.balance_threshold).await?;

// Get token holders from Bitquery API or mocked data.
let token_holders = if matches!(CONFIG.chain_id, 31337 | 1337) {
info!(
Expand Down
29 changes: 9 additions & 20 deletions examples/CRISP/server/src/server/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

use alloy::primitives::Address;
use anyhow::Result;
use num_bigint::BigUint;
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Deserialize, Debug)]
Expand Down Expand Up @@ -130,8 +128,12 @@ pub struct E3StateLite {

pub committee_public_key: Vec<u8>,
pub emojis: [String; 2],

pub token_address: String,
pub balance_threshold: String,
}


#[derive(Debug, Deserialize, Serialize)]
pub struct E3 {
// Identifiers
Expand Down Expand Up @@ -165,6 +167,9 @@ pub struct E3 {

// Emojis
pub emojis: [String; 2],

// Custom Parameters
pub custom_params: CustomParams,
}

#[derive(Debug, Deserialize, Serialize)]
Expand All @@ -176,6 +181,8 @@ pub struct E3Crisp {
pub votes_option_1: u64,
pub votes_option_2: u64,
pub token_holder_hashes: Vec<String>,
pub token_address: String,
pub balance_threshold: String,
}

impl From<E3> for WebResultRequest {
Expand All @@ -191,21 +198,3 @@ impl From<E3> for WebResultRequest {
}
}
}

impl From<E3> for E3StateLite {
fn from(e3: E3) -> Self {
E3StateLite {
id: e3.id,
chain_id: e3.chain_id,
enclave_address: e3.enclave_address,
status: e3.status,
vote_count: e3.vote_count,
start_time: e3.start_time,
start_block: e3.block_start,
duration: e3.duration,
expiration: e3.expiration,
committee_public_key: e3.committee_public_key,
emojis: e3.emojis,
}
}
}
37 changes: 10 additions & 27 deletions examples/CRISP/server/src/server/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,33 +85,13 @@ impl<S: DataStore> CrispE3Repository<S> {
}

pub async fn start_round(&mut self) -> Result<()> {
let start_time = chrono::Utc::now().timestamp() as u64;
let key = self.crisp_key();

self.store
.modify(&key, |e3_obj: Option<E3Crisp>| {
e3_obj.map(|mut e| {
e.start_time = start_time;
e
})
})
.await
.map_err(|_| eyre::eyre!("Could not update start_time for '{key}'"))?;

self.store
.modify(&key, |e3_obj: Option<E3Crisp>| {
e3_obj.map(|mut e| {
e.status = "Active".to_string();
e
})
})
.await
.map_err(|_| eyre::eyre!("Could not update status for '{key}'"))?;

Ok(())
let mut e3_crisp = self.get_crisp().await?;
e3_crisp.start_time = chrono::Utc::now().timestamp() as u64;
e3_crisp.status = "Active".to_string();
self.set_crisp(e3_crisp).await
}

pub async fn initialize_round(&mut self) -> Result<()> {
pub async fn initialize_round(&mut self, token_address: String, balance_threshold: String) -> Result<()> {
self.set_crisp(E3Crisp {
has_voted: vec![],
start_time: 0u64,
Expand All @@ -120,6 +100,8 @@ impl<S: DataStore> CrispE3Repository<S> {
votes_option_2: 0,
emojis: generate_emoji(),
token_holder_hashes: vec![],
token_address,
balance_threshold,
})
.await
}
Expand Down Expand Up @@ -208,6 +190,8 @@ impl<S: DataStore> CrispE3Repository<S> {
start_block: e3.request_block,
enclave_address: e3.enclave_address,
committee_public_key: e3.committee_public_key,
token_address: e3_crisp.token_address,
balance_threshold: e3_crisp.balance_threshold,
})
}

Expand Down Expand Up @@ -260,7 +244,6 @@ impl<S: DataStore> CrispE3Repository<S> {

pub async fn set_token_holder_hashes(&mut self, hashes: Vec<String>) -> Result<()> {
let key = self.crisp_key();

self.store
.modify(&key, |e3_obj: Option<E3Crisp>| {
e3_obj.map(|mut e| {
Expand All @@ -270,7 +253,7 @@ impl<S: DataStore> CrispE3Repository<S> {
})
.await
.map_err(|_| eyre::eyre!("Could not set token_holder_hashes for '{key}'"))?;

Ok(())
}

Expand Down
2 changes: 2 additions & 0 deletions packages/enclave-contracts/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ coverage.json
package-lock.json
pnpm-lock.yaml
yarn.lock

deployed_contracts.json
Loading