Skip to content

Commit

Permalink
Merge pull request #39 from JetonDAO/polling
Browse files Browse the repository at this point in the history
Get table and contracts data
  • Loading branch information
farzaamam authored Sep 26, 2024
2 parents 2ec471c + bfb2b78 commit 2c9468f
Show file tree
Hide file tree
Showing 11 changed files with 314 additions and 82 deletions.
2 changes: 0 additions & 2 deletions apps/web/src/app/@modal/(.)create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const INITIAL_FORM_VALUES: FormValues = {
maxPlayers: 10,
minBuyIn: 100,
maxBuyIn: 1000,
waitingBlocks: 0,
chipUnit: ChipUnits.apt,
};

Expand Down Expand Up @@ -59,7 +58,6 @@ export default function GameCreateModal() {
formValues.maxPlayers,
formValues.minBuyIn,
formValues.maxBuyIn,
formValues.waitingBlocks,
formValues.chipUnit,
account?.address,
signAndSubmitTransaction,
Expand Down
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
},
"style": {
"useNodejsImportProtocol": "off",
"useEnumInitializers": "off"
"useEnumInitializers": "off",
"noNonNullAssertion": "off"
}
}
},
Expand Down
8 changes: 0 additions & 8 deletions packages/ts-sdk/src/BettingManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ describe("tests different betting functionalities of betting manager", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};

Expand Down Expand Up @@ -73,7 +72,6 @@ describe("tests different betting functionalities of betting manager", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};

Expand Down Expand Up @@ -106,7 +104,6 @@ describe("tests different betting functionalities of betting manager", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};

Expand Down Expand Up @@ -156,7 +153,6 @@ describe("tests different betting functionalities of betting manager", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};

Expand Down Expand Up @@ -192,7 +188,6 @@ describe("tests different betting functionalities of betting manager", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};
const bettingManager = new BettingManager(
Expand Down Expand Up @@ -231,7 +226,6 @@ describe("testing different scenarios of self bet placing", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};
test("simply placing a bet early", () => {
Expand Down Expand Up @@ -353,7 +347,6 @@ describe("receiving different illegal bets", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};
const players: Player[] = [
Expand Down Expand Up @@ -394,7 +387,6 @@ describe("receiving different illegal bets", () => {
maxPlayers: 8,
minBuyIn: 400,
maxBuyIn: 2000,
waitingBlocks: 2,
chipUnit: ChipUnits.apt,
};
const players: Player[] = [
Expand Down
20 changes: 20 additions & 0 deletions packages/ts-sdk/src/PollingDataSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// import type { InputTransactionData } from "@aptos-labs/wallet-adapter-core";
// import type { PublicKey as ElGamalPublicKey } from "@jeton/zk-deck";
// import type { TableInfo } from "./types";
// import type { WholeGameState } from "./types/WholeGameState";

// export class PollingDataSource {
// constructor(
// private singAndSubmitTransaction: (transaction: InputTransactionData) => Promise<void>,
// private table: TableInfo,
// ) {}

// async getGameState(): Promise<WholeGameState> {
// //TODO:
// return {};
// }

// async checkIn(tableId: string, buyIn: number, elGamalPublicKey: ElGamalPublicKey) {}

// pollGameState(callback: (state: WholeGameState) => void) {}
// }
164 changes: 164 additions & 0 deletions packages/ts-sdk/src/PollingGame.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { EventEmitter } from "events";

import type {
InputTransactionData,
SignMessagePayload,
SignMessageResponse,
} from "@aptos-labs/wallet-adapter-core";

import {
type DecryptionCardShare,
type PublicKey as ElGamalPublicKey,
type Groth16Proof,
type ZKDeck,
createZKDeck,
} from "@jeton/zk-deck";

import { getUrlBytes, readData } from "./getURLBytes";

import type { TableInfo } from "./types";

import type { PollingDataSource } from "./PollingDataSource";
import {
type GameEventMap,
GameEventTypes,
type ReceivedPublicCardsEvent,
} from "./types/GameEvents";
import type { WholeGameState } from "./types/WholeGameState";
import { calculatePercentage } from "./utils/calculatePercentage";

export type ZkDeckUrls = {
shuffleEncryptDeckWasm: string;
decryptCardShareWasm: string;
shuffleEncryptDeckZkey: string;
decryptCardShareZkey: string;
};
export type GameConfigs = {
tableInfo: TableInfo;
address: string;
signMessage: (message: SignMessagePayload) => Promise<SignMessageResponse>;
signAndSubmitTransaction: (transaction: InputTransactionData) => Promise<void>;
onChainDataSource: PollingDataSource;
zkDeckFilesOrUrls: ZkDeckUrls;
};

export class PollingGame extends EventEmitter {
private onChainDataSource: PollingDataSource;

private tableInfo: TableInfo;
private playerId: string;
private signMessage: (message: SignMessagePayload) => Promise<SignMessageResponse>;
private signAndSubmitTransaction: (transaction: InputTransactionData) => Promise<void>;
// TODO: definitely assigned problem
private zkDeck?: ZKDeck;
private elGamalPublicKey?: ElGamalPublicKey;
private elGamalSecretKey?: bigint;

private creatingZKDeck: Promise<void>;

private gameState?: WholeGameState;

constructor(config: GameConfigs) {
super();
// wallet address of the user
this.playerId = config.address;

this.signMessage = config.signMessage;
this.signAndSubmitTransaction = config.signAndSubmitTransaction;

this.tableInfo = config.tableInfo;
this.onChainDataSource = config.onChainDataSource;
this.creatingZKDeck = this.createZKDeck(config.zkDeckFilesOrUrls);
}

private async createZKDeck(filesOrUrls: ZkDeckUrls) {
const [
decryptCardShareZkeyBytes,
shuffleEncryptDeckZkeyBytes,
decryptCardShareWasmBytes,
shuffleEncryptDeckWasmBytes,
] = await this.downloadZkeyFiles(filesOrUrls);

const zkDeck = await createZKDeck(
shuffleEncryptDeckWasmBytes,
decryptCardShareWasmBytes,
shuffleEncryptDeckZkeyBytes,
decryptCardShareZkeyBytes,
);
this.zkDeck = zkDeck;
this.elGamalSecretKey = zkDeck.sampleSecretKey();
this.elGamalPublicKey = zkDeck.generatePublicKey(this.elGamalSecretKey);
}

private async downloadZkeyFiles(urls: ZkDeckUrls) {
let decryptCardShareReceived = 0;
let decryptCardShareTotal: number;

let shuffleEncryptReceived = 0;
let shuffleEncryptTotal: number;

const [
decryptCardShareZkeyBytes,
shuffleEncryptDeckZkeyBytes,
decryptCardShareWasmBytes,
shuffleEncryptDeckWasmBytes,
] = await Promise.all([
getUrlBytes(urls.decryptCardShareZkey, (received, total) => {
decryptCardShareReceived = received;
decryptCardShareTotal = total;
if (decryptCardShareTotal && shuffleEncryptTotal)
this.emit(GameEventTypes.DOWNLOAD_PROGRESS, {
percentage: calculatePercentage(
[decryptCardShareReceived, shuffleEncryptReceived],
[decryptCardShareTotal, shuffleEncryptTotal],
),
});
}),
getUrlBytes(urls.shuffleEncryptDeckZkey, (received, total) => {
shuffleEncryptReceived = received;
shuffleEncryptTotal = total;
if (decryptCardShareTotal && shuffleEncryptTotal)
this.emit(GameEventTypes.DOWNLOAD_PROGRESS, {
percentage: calculatePercentage(
[decryptCardShareReceived, shuffleEncryptReceived],
[decryptCardShareTotal, shuffleEncryptTotal],
),
});
}),
readData(urls.decryptCardShareWasm),
readData(urls.shuffleEncryptDeckWasm),
]);
return [
decryptCardShareZkeyBytes,
shuffleEncryptDeckZkeyBytes,
decryptCardShareWasmBytes,
shuffleEncryptDeckWasmBytes,
] as const;
}

private isAlreadyCheckedIn(state: WholeGameState): boolean {
//TODO:
return false;
}

private receivedGameState = (gameState: WholeGameState) => {};

public async checkIn(buyIn?: number) {
await this.creatingZKDeck;
if (!this.elGamalPublicKey) throw new Error("you must first create elGamal keys");

const currentGameState = await this.onChainDataSource.getGameState();
const alreadyCheckedIn = this.isAlreadyCheckedIn(currentGameState);

if (buyIn && !alreadyCheckedIn) {
await this.onChainDataSource.checkIn(this.tableInfo.id, buyIn, this.elGamalPublicKey);
} else if (!alreadyCheckedIn && !buyIn) {
throw new Error("Game Error");
}

this.onChainDataSource.pollGameState(this.receivedGameState);
this.gameState = await this.onChainDataSource.getGameState();
// TODO: return game state to ui
this.receivedGameState(this.gameState);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ export const contractAddress = process.env.NEXT_PUBLIC_CONTRACTS_ADDR as string;
const appName = "texas_holdem";
const tableCreatedEvent = "TableCreatedEvent";
const tableType = "Table";

export const contractTableCreatedEventType =
`${contractAddress}::${appName}::${tableCreatedEvent}` as MoveStructId;
export const contractTableType = `${contractAddress}::${appName}::${tableType}` as MoveStructId;
const createTable = "create_table:";
export const contractCreateTable = `${contractAddress}::${appName}::${createTable}` as MoveStructId;

const createTable = "create_table";
export const contractCreateTableFunctionName =
`${contractAddress}::${appName}::${createTable}` as MoveStructId;
22 changes: 22 additions & 0 deletions packages/ts-sdk/src/contracts/contractDataMapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ChipUnits, type TableInfo } from "@src/types";

// biome-ignore lint/suspicious/noExplicitAny: <explanation>
type Table = any;

export const createTableInfo = (
tableObjectAddress: string,
tableObjectResource: Table,
): TableInfo => {
//TODO check maxPlayers and minPlayers value
const tableInfo: TableInfo = {
id: tableObjectAddress,
smallBlind: tableObjectResource.small_blind,
numberOfRaises: tableObjectResource.num_raises,
minPlayers: tableObjectResource.start_at_player,
maxPlayers: tableObjectResource.start_at_player,
minBuyIn: tableObjectResource.min_buy_in_amount,
maxBuyIn: tableObjectResource.max_buy_in_amount,
chipUnit: ChipUnits.apt,
};
return tableInfo;
};
70 changes: 70 additions & 0 deletions packages/ts-sdk/src/contracts/contractInteractions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { GetEventsResponse } from "@aptos-labs/ts-sdk";
import type { WriteSetChange, WriteSetChangeWriteResource } from "@aptos-labs/ts-sdk";
import { ChipUnits, TableInfo } from "@src/types";
import { aptos } from "@src/utils/aptos";
import {
contractCreateTableFunctionName,
contractTableCreatedEventType,
contractTableType,
} from "./contractData";

//TODO apply pagination for getModuleEventsByEventType
export const getTableObjectAddresses = async (): Promise<GetEventsResponse> => {
return aptos.getModuleEventsByEventType({
eventType: contractTableCreatedEventType,
});
};

export const getTableObject = async (tableObjectAddress: string): Promise<GetEventsResponse> => {
return aptos.getAccountResource({
accountAddress: tableObjectAddress,
resourceType: contractTableType,
});
};

export const createTableObject = async (
smallBlind: number,
numberOfRaises: number,
minPlayers: number,
minBuyIn: number,
maxBuyIn: number,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
accountAddress: any,
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
signAndSubmitTransaction: any,
): Promise<[string, GetEventsResponse]> => {
const submitCreateTableTransactionHash = await signAndSubmitTransaction({
sender: accountAddress,
data: {
function: contractCreateTableFunctionName,
functionArguments: [
1000,
minBuyIn,
maxBuyIn,
2 * 60,
smallBlind,
numberOfRaises,
8,
minPlayers,
],
},
});

const transactionData = await aptos.waitForTransaction({
transactionHash: submitCreateTableTransactionHash.hash,
});

const tableObjectAddress = transactionData.changes.find((change) =>
isWriteSetChangeWriteResource(change),
)!.address;

const tableObjectResource = await getTableObject(tableObjectAddress);

return [tableObjectAddress, tableObjectResource];
};

function isWriteSetChangeWriteResource(
write: WriteSetChange,
): write is WriteSetChangeWriteResource {
return (write as WriteSetChangeWriteResource) !== undefined;
}
Loading

0 comments on commit 2c9468f

Please sign in to comment.