@peeramid-labs/sdk 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/cli/abis/EIP712.js +72 -0
- package/cli/abis/EIP712.js.map +1 -0
- package/cli/abis/ERC20Capped.js +355 -0
- package/cli/abis/ERC20Capped.js.map +1 -0
- package/cli/abis/ERC20Votes.js +774 -0
- package/cli/abis/ERC20Votes.js.map +1 -0
- package/cli/abis/IErrors.js +16 -0
- package/cli/abis/IErrors.js.map +1 -1
- package/cli/abis/IPoseidon2.js +26 -0
- package/cli/abis/IPoseidon2.js.map +1 -0
- package/cli/abis/IPoseidon5.js +26 -0
- package/cli/abis/IPoseidon5.js.map +1 -0
- package/cli/abis/IPoseidon6.js +26 -0
- package/cli/abis/IPoseidon6.js.map +1 -0
- package/cli/abis/IRankifyInstance.js +13 -1
- package/cli/abis/IRankifyInstance.js.map +1 -1
- package/cli/abis/MAODistribution.js +5 -0
- package/cli/abis/MAODistribution.js.map +1 -1
- package/cli/abis/Nonces.js +42 -0
- package/cli/abis/Nonces.js.map +1 -0
- package/cli/abis/ProposalsIntegrity15Groth16Verifier.js +1120 -0
- package/cli/abis/ProposalsIntegrity15Groth16Verifier.js.map +1 -0
- package/cli/abis/Rankify.js +499 -0
- package/cli/abis/Rankify.js.map +1 -1
- package/cli/abis/RankifyDiamondInstance.js +323 -14
- package/cli/abis/RankifyDiamondInstance.js.map +1 -1
- package/cli/abis/RankifyInstanceEventMock.js +1 -1
- package/cli/abis/RankifyInstanceEventMock.js.map +1 -1
- package/cli/abis/RankifyInstanceGameMastersFacet.js +132 -13
- package/cli/abis/RankifyInstanceGameMastersFacet.js.map +1 -1
- package/cli/abis/RankifyInstanceInit.js +20 -0
- package/cli/abis/RankifyInstanceInit.js.map +1 -1
- package/cli/abis/RankifyInstanceMainFacet.js +125 -1
- package/cli/abis/RankifyInstanceMainFacet.js.map +1 -1
- package/cli/abis/RankifyInstanceRequirementsFacet.js +25 -0
- package/cli/abis/RankifyInstanceRequirementsFacet.js.map +1 -1
- package/cli/abis/Votes.js +395 -0
- package/cli/abis/Votes.js.map +1 -0
- package/cli/abis/index.js +44 -4
- package/cli/abis/index.js.map +1 -1
- package/cli/abis/superinterface.js +2237 -0
- package/cli/abis/superinterface.js.map +1 -0
- package/cli/cli/commands/distributions/add.js +2 -2
- package/cli/cli/commands/distributions/add.js.map +1 -1
- package/cli/cli/commands/eds/index.js +14 -0
- package/cli/cli/commands/eds/index.js.map +1 -1
- package/cli/cli/commands/fellowship/create.js +0 -1
- package/cli/cli/commands/fellowship/create.js.map +1 -1
- package/cli/cli/index.js +2 -0
- package/cli/cli/index.js.map +1 -1
- package/cli/eds/Distributor.js +12 -5
- package/cli/eds/Distributor.js.map +1 -1
- package/cli/rankify/InstanceBase.js +199 -42
- package/cli/rankify/InstanceBase.js.map +1 -1
- package/cli/rankify/MAODistributor.js +17 -0
- package/cli/rankify/MAODistributor.js.map +1 -1
- package/cli/types.js +22 -1
- package/cli/types.js.map +1 -1
- package/cli/utils/ApiError.js +2 -1
- package/cli/utils/ApiError.js.map +1 -1
- package/cli/utils/artifacts.js +19 -0
- package/cli/utils/artifacts.js.map +1 -1
- package/cli/utils/chainMapping.js +1 -0
- package/cli/utils/chainMapping.js.map +1 -1
- package/cli/utils/log.js +26 -0
- package/cli/utils/log.js.map +1 -0
- package/cli/utils/permutations.js +32 -0
- package/cli/utils/permutations.js.map +1 -0
- package/docs/classes/GameMaster.md +377 -79
- package/docs/classes/InstanceBase.md +169 -14
- package/docs/classes/InstancePlayer.md +366 -36
- package/docs/classes/MAODistributorClient.md +21 -0
- package/docs/docs/classes/GameMaster.md +377 -79
- package/docs/docs/classes/InstanceBase.md +169 -14
- package/docs/docs/classes/InstancePlayer.md +366 -36
- package/docs/docs/classes/MAODistributorClient.md +21 -0
- package/docs/docs/index.md +67 -15
- package/docs/docs/interfaces/GameMetadata.md +91 -0
- package/docs/docs/interfaces/GmProposalParams.md +41 -0
- package/docs/docs/interfaces/Submission.md +52 -0
- package/docs/index.md +67 -15
- package/docs/interfaces/GameMetadata.md +91 -0
- package/docs/interfaces/GmProposalParams.md +41 -0
- package/docs/interfaces/Submission.md +52 -0
- package/lib.commonjs/abis/EIP712.d.ts +54 -0
- package/lib.commonjs/abis/EIP712.d.ts.map +1 -0
- package/lib.commonjs/abis/EIP712.js +72 -0
- package/lib.commonjs/abis/EIP712.js.map +1 -0
- package/lib.commonjs/abis/ERC20Capped.d.ts +267 -0
- package/lib.commonjs/abis/ERC20Capped.d.ts.map +1 -0
- package/lib.commonjs/abis/ERC20Capped.js +355 -0
- package/lib.commonjs/abis/ERC20Capped.js.map +1 -0
- package/lib.commonjs/abis/ERC20Votes.d.ts +587 -0
- package/lib.commonjs/abis/ERC20Votes.d.ts.map +1 -0
- package/lib.commonjs/abis/ERC20Votes.js +774 -0
- package/lib.commonjs/abis/ERC20Votes.js.map +1 -0
- package/lib.commonjs/abis/IErrors.d.ts +12 -0
- package/lib.commonjs/abis/IErrors.d.ts.map +1 -1
- package/lib.commonjs/abis/IErrors.js +16 -0
- package/lib.commonjs/abis/IErrors.js.map +1 -1
- package/lib.commonjs/abis/IPoseidon2.d.ts +17 -0
- package/lib.commonjs/abis/IPoseidon2.d.ts.map +1 -0
- package/lib.commonjs/abis/IPoseidon2.js +26 -0
- package/lib.commonjs/abis/IPoseidon2.js.map +1 -0
- package/lib.commonjs/abis/IPoseidon5.d.ts +17 -0
- package/lib.commonjs/abis/IPoseidon5.d.ts.map +1 -0
- package/lib.commonjs/abis/IPoseidon5.js +26 -0
- package/lib.commonjs/abis/IPoseidon5.js.map +1 -0
- package/lib.commonjs/abis/IPoseidon6.d.ts +17 -0
- package/lib.commonjs/abis/IPoseidon6.d.ts.map +1 -0
- package/lib.commonjs/abis/IPoseidon6.js +26 -0
- package/lib.commonjs/abis/IPoseidon6.js.map +1 -0
- package/lib.commonjs/abis/IRankifyInstance.d.ts +11 -1
- package/lib.commonjs/abis/IRankifyInstance.d.ts.map +1 -1
- package/lib.commonjs/abis/IRankifyInstance.js +13 -1
- package/lib.commonjs/abis/IRankifyInstance.js.map +1 -1
- package/lib.commonjs/abis/MAODistribution.d.ts +4 -0
- package/lib.commonjs/abis/MAODistribution.d.ts.map +1 -1
- package/lib.commonjs/abis/MAODistribution.js +5 -0
- package/lib.commonjs/abis/MAODistribution.js.map +1 -1
- package/lib.commonjs/abis/Nonces.d.ts +29 -0
- package/lib.commonjs/abis/Nonces.d.ts.map +1 -0
- package/lib.commonjs/abis/Nonces.js +42 -0
- package/lib.commonjs/abis/Nonces.js.map +1 -0
- package/lib.commonjs/abis/ProposalsIntegrity15Groth16Verifier.d.ts +859 -0
- package/lib.commonjs/abis/ProposalsIntegrity15Groth16Verifier.d.ts.map +1 -0
- package/lib.commonjs/abis/ProposalsIntegrity15Groth16Verifier.js +1120 -0
- package/lib.commonjs/abis/ProposalsIntegrity15Groth16Verifier.js.map +1 -0
- package/lib.commonjs/abis/Rankify.d.ts +380 -0
- package/lib.commonjs/abis/Rankify.d.ts.map +1 -1
- package/lib.commonjs/abis/Rankify.js +499 -0
- package/lib.commonjs/abis/Rankify.js.map +1 -1
- package/lib.commonjs/abis/RankifyDiamondInstance.d.ts +254 -14
- package/lib.commonjs/abis/RankifyDiamondInstance.d.ts.map +1 -1
- package/lib.commonjs/abis/RankifyDiamondInstance.js +323 -14
- package/lib.commonjs/abis/RankifyDiamondInstance.js.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceEventMock.d.ts +1 -1
- package/lib.commonjs/abis/RankifyInstanceEventMock.js +1 -1
- package/lib.commonjs/abis/RankifyInstanceEventMock.js.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceGameMastersFacet.d.ts +107 -13
- package/lib.commonjs/abis/RankifyInstanceGameMastersFacet.d.ts.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceGameMastersFacet.js +132 -13
- package/lib.commonjs/abis/RankifyInstanceGameMastersFacet.js.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceInit.d.ts +16 -0
- package/lib.commonjs/abis/RankifyInstanceInit.d.ts.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceInit.js +20 -0
- package/lib.commonjs/abis/RankifyInstanceInit.js.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceMainFacet.d.ts +97 -1
- package/lib.commonjs/abis/RankifyInstanceMainFacet.d.ts.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceMainFacet.js +125 -1
- package/lib.commonjs/abis/RankifyInstanceMainFacet.js.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceRequirementsFacet.d.ts +20 -0
- package/lib.commonjs/abis/RankifyInstanceRequirementsFacet.d.ts.map +1 -1
- package/lib.commonjs/abis/RankifyInstanceRequirementsFacet.js +25 -0
- package/lib.commonjs/abis/RankifyInstanceRequirementsFacet.js.map +1 -1
- package/lib.commonjs/abis/Votes.d.ts +300 -0
- package/lib.commonjs/abis/Votes.d.ts.map +1 -0
- package/lib.commonjs/abis/Votes.js +395 -0
- package/lib.commonjs/abis/Votes.js.map +1 -0
- package/lib.commonjs/abis/index.d.ts +12570 -9558
- package/lib.commonjs/abis/index.d.ts.map +1 -1
- package/lib.commonjs/abis/index.js +44 -4
- package/lib.commonjs/abis/index.js.map +1 -1
- package/lib.commonjs/abis/superinterface.d.ts +3 -0
- package/lib.commonjs/abis/superinterface.d.ts.map +1 -0
- package/lib.commonjs/abis/superinterface.js +2237 -0
- package/lib.commonjs/abis/superinterface.js.map +1 -0
- package/lib.commonjs/eds/Distributor.d.ts +1 -0
- package/lib.commonjs/eds/Distributor.d.ts.map +1 -1
- package/lib.commonjs/eds/Distributor.js +12 -5
- package/lib.commonjs/eds/Distributor.js.map +1 -1
- package/lib.commonjs/index.d.ts +1 -2
- package/lib.commonjs/index.d.ts.map +1 -1
- package/lib.commonjs/index.js +1 -4
- package/lib.commonjs/index.js.map +1 -1
- package/lib.commonjs/rankify/GameMaster.d.ts +289 -43
- package/lib.commonjs/rankify/GameMaster.d.ts.map +1 -1
- package/lib.commonjs/rankify/GameMaster.js +794 -122
- package/lib.commonjs/rankify/GameMaster.js.map +1 -1
- package/lib.commonjs/rankify/InstanceBase.d.ts +1406 -3434
- package/lib.commonjs/rankify/InstanceBase.d.ts.map +1 -1
- package/lib.commonjs/rankify/InstanceBase.js +200 -42
- package/lib.commonjs/rankify/InstanceBase.js.map +1 -1
- package/lib.commonjs/rankify/MAODistributor.d.ts.map +1 -1
- package/lib.commonjs/rankify/MAODistributor.js +17 -0
- package/lib.commonjs/rankify/MAODistributor.js.map +1 -1
- package/lib.commonjs/rankify/Player.d.ts +80 -2
- package/lib.commonjs/rankify/Player.d.ts.map +1 -1
- package/lib.commonjs/rankify/Player.js +138 -4
- package/lib.commonjs/rankify/Player.js.map +1 -1
- package/lib.commonjs/types/contracts.d.ts +18 -0
- package/lib.commonjs/types/contracts.d.ts.map +1 -1
- package/lib.commonjs/types.d.ts +68 -6
- package/lib.commonjs/types.d.ts.map +1 -1
- package/lib.commonjs/types.js +22 -1
- package/lib.commonjs/types.js.map +1 -1
- package/lib.commonjs/utils/ApiError.d.ts.map +1 -1
- package/lib.commonjs/utils/ApiError.js +2 -1
- package/lib.commonjs/utils/ApiError.js.map +1 -1
- package/lib.commonjs/utils/artifacts.d.ts +4 -2
- package/lib.commonjs/utils/artifacts.d.ts.map +1 -1
- package/lib.commonjs/utils/artifacts.js +19 -0
- package/lib.commonjs/utils/artifacts.js.map +1 -1
- package/lib.commonjs/utils/chainMapping.d.ts.map +1 -1
- package/lib.commonjs/utils/chainMapping.js +1 -0
- package/lib.commonjs/utils/chainMapping.js.map +1 -1
- package/lib.commonjs/utils/getEnv.d.ts +9 -0
- package/lib.commonjs/utils/getEnv.d.ts.map +1 -0
- package/lib.commonjs/utils/getEnv.js +18 -0
- package/lib.commonjs/utils/getEnv.js.map +1 -0
- package/lib.commonjs/utils/log.d.ts +2 -0
- package/lib.commonjs/utils/log.d.ts.map +1 -0
- package/lib.commonjs/utils/log.js +26 -0
- package/lib.commonjs/utils/log.js.map +1 -0
- package/lib.commonjs/utils/permutations.d.ts +21 -0
- package/lib.commonjs/utils/permutations.d.ts.map +1 -0
- package/lib.commonjs/utils/permutations.js +32 -0
- package/lib.commonjs/utils/permutations.js.map +1 -0
- package/lib.esm/abis/EIP712.d.ts +54 -0
- package/lib.esm/abis/EIP712.d.ts.map +1 -0
- package/lib.esm/abis/EIP712.js +69 -0
- package/lib.esm/abis/EIP712.js.map +1 -0
- package/lib.esm/abis/ERC20Capped.d.ts +267 -0
- package/lib.esm/abis/ERC20Capped.d.ts.map +1 -0
- package/lib.esm/abis/ERC20Capped.js +352 -0
- package/lib.esm/abis/ERC20Capped.js.map +1 -0
- package/lib.esm/abis/ERC20Votes.d.ts +587 -0
- package/lib.esm/abis/ERC20Votes.d.ts.map +1 -0
- package/lib.esm/abis/ERC20Votes.js +771 -0
- package/lib.esm/abis/ERC20Votes.js.map +1 -0
- package/lib.esm/abis/IErrors.d.ts +12 -0
- package/lib.esm/abis/IErrors.d.ts.map +1 -1
- package/lib.esm/abis/IErrors.js +16 -0
- package/lib.esm/abis/IErrors.js.map +1 -1
- package/lib.esm/abis/IPoseidon2.d.ts +17 -0
- package/lib.esm/abis/IPoseidon2.d.ts.map +1 -0
- package/lib.esm/abis/IPoseidon2.js +23 -0
- package/lib.esm/abis/IPoseidon2.js.map +1 -0
- package/lib.esm/abis/IPoseidon5.d.ts +17 -0
- package/lib.esm/abis/IPoseidon5.d.ts.map +1 -0
- package/lib.esm/abis/IPoseidon5.js +23 -0
- package/lib.esm/abis/IPoseidon5.js.map +1 -0
- package/lib.esm/abis/IPoseidon6.d.ts +17 -0
- package/lib.esm/abis/IPoseidon6.d.ts.map +1 -0
- package/lib.esm/abis/IPoseidon6.js +23 -0
- package/lib.esm/abis/IPoseidon6.js.map +1 -0
- package/lib.esm/abis/IRankifyInstance.d.ts +11 -1
- package/lib.esm/abis/IRankifyInstance.d.ts.map +1 -1
- package/lib.esm/abis/IRankifyInstance.js +13 -1
- package/lib.esm/abis/IRankifyInstance.js.map +1 -1
- package/lib.esm/abis/MAODistribution.d.ts +4 -0
- package/lib.esm/abis/MAODistribution.d.ts.map +1 -1
- package/lib.esm/abis/MAODistribution.js +5 -0
- package/lib.esm/abis/MAODistribution.js.map +1 -1
- package/lib.esm/abis/Nonces.d.ts +29 -0
- package/lib.esm/abis/Nonces.d.ts.map +1 -0
- package/lib.esm/abis/Nonces.js +39 -0
- package/lib.esm/abis/Nonces.js.map +1 -0
- package/lib.esm/abis/ProposalsIntegrity15Groth16Verifier.d.ts +859 -0
- package/lib.esm/abis/ProposalsIntegrity15Groth16Verifier.d.ts.map +1 -0
- package/lib.esm/abis/ProposalsIntegrity15Groth16Verifier.js +1117 -0
- package/lib.esm/abis/ProposalsIntegrity15Groth16Verifier.js.map +1 -0
- package/lib.esm/abis/Rankify.d.ts +380 -0
- package/lib.esm/abis/Rankify.d.ts.map +1 -1
- package/lib.esm/abis/Rankify.js +499 -0
- package/lib.esm/abis/Rankify.js.map +1 -1
- package/lib.esm/abis/RankifyDiamondInstance.d.ts +254 -14
- package/lib.esm/abis/RankifyDiamondInstance.d.ts.map +1 -1
- package/lib.esm/abis/RankifyDiamondInstance.js +323 -14
- package/lib.esm/abis/RankifyDiamondInstance.js.map +1 -1
- package/lib.esm/abis/RankifyInstanceEventMock.d.ts +1 -1
- package/lib.esm/abis/RankifyInstanceEventMock.js +1 -1
- package/lib.esm/abis/RankifyInstanceEventMock.js.map +1 -1
- package/lib.esm/abis/RankifyInstanceGameMastersFacet.d.ts +107 -13
- package/lib.esm/abis/RankifyInstanceGameMastersFacet.d.ts.map +1 -1
- package/lib.esm/abis/RankifyInstanceGameMastersFacet.js +132 -13
- package/lib.esm/abis/RankifyInstanceGameMastersFacet.js.map +1 -1
- package/lib.esm/abis/RankifyInstanceInit.d.ts +16 -0
- package/lib.esm/abis/RankifyInstanceInit.d.ts.map +1 -1
- package/lib.esm/abis/RankifyInstanceInit.js +20 -0
- package/lib.esm/abis/RankifyInstanceInit.js.map +1 -1
- package/lib.esm/abis/RankifyInstanceMainFacet.d.ts +97 -1
- package/lib.esm/abis/RankifyInstanceMainFacet.d.ts.map +1 -1
- package/lib.esm/abis/RankifyInstanceMainFacet.js +125 -1
- package/lib.esm/abis/RankifyInstanceMainFacet.js.map +1 -1
- package/lib.esm/abis/RankifyInstanceRequirementsFacet.d.ts +20 -0
- package/lib.esm/abis/RankifyInstanceRequirementsFacet.d.ts.map +1 -1
- package/lib.esm/abis/RankifyInstanceRequirementsFacet.js +25 -0
- package/lib.esm/abis/RankifyInstanceRequirementsFacet.js.map +1 -1
- package/lib.esm/abis/Votes.d.ts +300 -0
- package/lib.esm/abis/Votes.d.ts.map +1 -0
- package/lib.esm/abis/Votes.js +392 -0
- package/lib.esm/abis/Votes.js.map +1 -0
- package/lib.esm/abis/index.d.ts +12570 -9558
- package/lib.esm/abis/index.d.ts.map +1 -1
- package/lib.esm/abis/index.js +31 -1
- package/lib.esm/abis/index.js.map +1 -1
- package/lib.esm/abis/superinterface.d.ts +3 -0
- package/lib.esm/abis/superinterface.d.ts.map +1 -0
- package/lib.esm/abis/superinterface.js +2234 -0
- package/lib.esm/abis/superinterface.js.map +1 -0
- package/lib.esm/eds/Distributor.d.ts +1 -0
- package/lib.esm/eds/Distributor.d.ts.map +1 -1
- package/lib.esm/eds/Distributor.js +12 -5
- package/lib.esm/eds/Distributor.js.map +1 -1
- package/lib.esm/index.d.ts +1 -2
- package/lib.esm/index.d.ts.map +1 -1
- package/lib.esm/index.js +0 -2
- package/lib.esm/index.js.map +1 -1
- package/lib.esm/rankify/GameMaster.d.ts +289 -43
- package/lib.esm/rankify/GameMaster.d.ts.map +1 -1
- package/lib.esm/rankify/GameMaster.js +795 -123
- package/lib.esm/rankify/GameMaster.js.map +1 -1
- package/lib.esm/rankify/InstanceBase.d.ts +1406 -3434
- package/lib.esm/rankify/InstanceBase.d.ts.map +1 -1
- package/lib.esm/rankify/InstanceBase.js +186 -27
- package/lib.esm/rankify/InstanceBase.js.map +1 -1
- package/lib.esm/rankify/MAODistributor.d.ts.map +1 -1
- package/lib.esm/rankify/MAODistributor.js +18 -1
- package/lib.esm/rankify/MAODistributor.js.map +1 -1
- package/lib.esm/rankify/Player.d.ts +80 -2
- package/lib.esm/rankify/Player.d.ts.map +1 -1
- package/lib.esm/rankify/Player.js +138 -4
- package/lib.esm/rankify/Player.js.map +1 -1
- package/lib.esm/types/contracts.d.ts +18 -0
- package/lib.esm/types/contracts.d.ts.map +1 -1
- package/lib.esm/types.d.ts +68 -6
- package/lib.esm/types.d.ts.map +1 -1
- package/lib.esm/types.js +21 -0
- package/lib.esm/types.js.map +1 -1
- package/lib.esm/utils/ApiError.d.ts.map +1 -1
- package/lib.esm/utils/ApiError.js +2 -1
- package/lib.esm/utils/ApiError.js.map +1 -1
- package/lib.esm/utils/artifacts.d.ts +4 -2
- package/lib.esm/utils/artifacts.d.ts.map +1 -1
- package/lib.esm/utils/artifacts.js +19 -0
- package/lib.esm/utils/artifacts.js.map +1 -1
- package/lib.esm/utils/chainMapping.d.ts.map +1 -1
- package/lib.esm/utils/chainMapping.js +1 -0
- package/lib.esm/utils/chainMapping.js.map +1 -1
- package/lib.esm/utils/getEnv.d.ts +9 -0
- package/lib.esm/utils/getEnv.d.ts.map +1 -0
- package/lib.esm/utils/getEnv.js +15 -0
- package/lib.esm/utils/getEnv.js.map +1 -0
- package/lib.esm/utils/log.d.ts +2 -0
- package/lib.esm/utils/log.d.ts.map +1 -0
- package/lib.esm/utils/log.js +20 -0
- package/lib.esm/utils/log.js.map +1 -0
- package/lib.esm/utils/permutations.d.ts +21 -0
- package/lib.esm/utils/permutations.d.ts.map +1 -0
- package/lib.esm/utils/permutations.js +27 -0
- package/lib.esm/utils/permutations.js.map +1 -0
- package/package.json +16 -9
|
@@ -7,7 +7,16 @@ exports.GameMaster = void 0;
|
|
|
7
7
|
const viem_1 = require("viem");
|
|
8
8
|
const abis_1 = require("../abis");
|
|
9
9
|
const InstanceBase_1 = __importDefault(require("./InstanceBase"));
|
|
10
|
+
const types_1 = require("../types");
|
|
10
11
|
const utils_1 = require("../utils");
|
|
12
|
+
const accounts_1 = require("viem/accounts");
|
|
13
|
+
const log_1 = require("../utils/log");
|
|
14
|
+
const circomlibjs_1 = require("circomlibjs");
|
|
15
|
+
const aes_1 = __importDefault(require("crypto-js/aes"));
|
|
16
|
+
const crypto_js_1 = __importDefault(require("crypto-js"));
|
|
17
|
+
const zkit_1 = require("@solarity/zkit");
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
19
|
+
const permutations_1 = require("../utils/permutations");
|
|
11
20
|
/**
|
|
12
21
|
* GameMaster class for managing game state and cryptographic operations in Rankify
|
|
13
22
|
* Extends InstanceBase to provide game master specific functionality
|
|
@@ -16,10 +25,6 @@ const utils_1 = require("../utils");
|
|
|
16
25
|
class GameMaster {
|
|
17
26
|
walletClient;
|
|
18
27
|
publicClient;
|
|
19
|
-
encryptionCallback;
|
|
20
|
-
decryptionCallback;
|
|
21
|
-
randomnessCallback;
|
|
22
|
-
turnSaltCallback;
|
|
23
28
|
chainId;
|
|
24
29
|
/**
|
|
25
30
|
* Creates a new GameMaster instance
|
|
@@ -27,20 +32,41 @@ class GameMaster {
|
|
|
27
32
|
* @param walletClient - Viem wallet client for transactions
|
|
28
33
|
* @param publicClient - Viem public client for reading state
|
|
29
34
|
* @param chainId - Chain ID of the network
|
|
30
|
-
* @param encryptionCallback - Callback function for encrypting data
|
|
31
|
-
* @param decryptionCallback - Callback function for decrypting data
|
|
32
|
-
* @param randomnessCallback - Callback function for generating random numbers
|
|
33
|
-
* @param turnSaltCallback - Callback function for generating turn salts
|
|
34
35
|
*/
|
|
35
|
-
constructor({ walletClient, chainId, publicClient,
|
|
36
|
+
constructor({ walletClient, chainId, publicClient, }) {
|
|
36
37
|
this.chainId = chainId;
|
|
37
38
|
this.publicClient = publicClient;
|
|
38
39
|
this.walletClient = walletClient;
|
|
39
|
-
this.encryptionCallback = encryptionCallback;
|
|
40
|
-
this.decryptionCallback = decryptionCallback;
|
|
41
|
-
this.randomnessCallback = randomnessCallback;
|
|
42
|
-
this.turnSaltCallback = turnSaltCallback;
|
|
43
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Decrypts a proposal for a specific game turn
|
|
43
|
+
* @param proposal - The encrypted proposal
|
|
44
|
+
* @param turn - The turn number
|
|
45
|
+
* @param instanceAddress - The address of the instance
|
|
46
|
+
* @param gameId - The ID of the game
|
|
47
|
+
* @param proposer - The address of the proposer
|
|
48
|
+
* @returns The decrypted proposal
|
|
49
|
+
*/
|
|
50
|
+
decryptProposal = async ({ proposal, turn, instanceAddress, gameId, proposer, instance, }) => {
|
|
51
|
+
const _instance = instance ?? new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
52
|
+
const proposerPubKey = await _instance.getPlayerPubKey({
|
|
53
|
+
instanceAddress,
|
|
54
|
+
gameId,
|
|
55
|
+
player: proposer,
|
|
56
|
+
});
|
|
57
|
+
const sharedKey = _instance.sharedSigner({
|
|
58
|
+
publicKey: proposerPubKey,
|
|
59
|
+
privateKey: await this.gameKey({ gameId, contractAddress: instanceAddress }),
|
|
60
|
+
gameId,
|
|
61
|
+
turn,
|
|
62
|
+
contractAddress: instanceAddress,
|
|
63
|
+
chainId: this.chainId,
|
|
64
|
+
});
|
|
65
|
+
(0, log_1.logger)(`Decrypting proposal ${proposal} with shared key (hashed value: ${(0, viem_1.keccak256)(sharedKey)})`);
|
|
66
|
+
const decryptedProposal = aes_1.default.decrypt(proposal, sharedKey).toString(crypto_js_1.default.enc.Utf8);
|
|
67
|
+
(0, log_1.logger)(`Decrypted proposal ${decryptedProposal}`);
|
|
68
|
+
return decryptedProposal;
|
|
69
|
+
};
|
|
44
70
|
/**
|
|
45
71
|
* Decrypts proposals for a specific game turn
|
|
46
72
|
* @param gameId - ID of the game
|
|
@@ -54,55 +80,201 @@ class GameMaster {
|
|
|
54
80
|
address: instanceAddress,
|
|
55
81
|
eventName: "ProposalSubmitted",
|
|
56
82
|
args: { gameId: gameId, turn: turn, proposer: proposer },
|
|
83
|
+
fromBlock: 0n,
|
|
57
84
|
});
|
|
85
|
+
const instance = new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
58
86
|
if (evts.length == 0)
|
|
59
87
|
return [];
|
|
88
|
+
(0, log_1.logger)(`Decrypting ${evts.length} proposals`);
|
|
60
89
|
const proposals = await Promise.all(evts.map(async (log) => {
|
|
61
|
-
|
|
90
|
+
(0, log_1.logger)(`Decrypting proposal ${log.args.proposer}`);
|
|
91
|
+
if (!log.args.proposer)
|
|
92
|
+
throw new Error("No proposer");
|
|
93
|
+
if (!log.args.encryptedProposal)
|
|
62
94
|
throw new Error("No proposalEncryptedByGM");
|
|
63
95
|
return {
|
|
64
96
|
proposer: log.args.proposer,
|
|
65
|
-
proposal: await this.
|
|
97
|
+
proposal: await this.decryptProposal({
|
|
98
|
+
proposal: log.args.encryptedProposal,
|
|
99
|
+
turn: turn,
|
|
100
|
+
instanceAddress: instanceAddress,
|
|
101
|
+
gameId: gameId,
|
|
102
|
+
proposer: log.args.proposer,
|
|
103
|
+
instance,
|
|
104
|
+
}),
|
|
66
105
|
};
|
|
67
106
|
}));
|
|
68
107
|
return proposals;
|
|
69
108
|
};
|
|
70
109
|
/**
|
|
71
|
-
*
|
|
72
|
-
* @param
|
|
73
|
-
* @
|
|
110
|
+
* Generates a deterministic permutation for a specific game turn
|
|
111
|
+
* @param gameId - ID of the game
|
|
112
|
+
* @param turn - Turn number
|
|
113
|
+
* @param size - Size of the permutation
|
|
114
|
+
* @param verifierAddress - Address of the verifier
|
|
115
|
+
* @returns The generated permutation, secret, and commitment
|
|
74
116
|
*/
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
|
|
117
|
+
getPermutation = async ({ gameId, turn, size, verifierAddress, }) => {
|
|
118
|
+
const maxSize = 15;
|
|
119
|
+
const turnSalt = await this.getTurnSalt({ gameId, turn, verifierAddress });
|
|
120
|
+
// Create deterministic seed from game parameters and GM's signature
|
|
121
|
+
// Use the seed to generate permutation
|
|
122
|
+
const permutation = Array.from({ length: maxSize }, (_, i) => i);
|
|
123
|
+
// Fisher-Yates shuffle with deterministic randomness
|
|
124
|
+
for (let i = size - 1; i >= 0; i--) {
|
|
125
|
+
// Generate deterministic random number for this position
|
|
126
|
+
const randHash = (0, viem_1.keccak256)((0, viem_1.encodePacked)(["uint256", "uint256"], [turnSalt, BigInt(i)]));
|
|
127
|
+
const rand = BigInt(randHash);
|
|
128
|
+
const j = Number(rand % BigInt(i + 1));
|
|
129
|
+
// Swap elements
|
|
130
|
+
[permutation[i], permutation[j]] = [permutation[j], permutation[i]];
|
|
131
|
+
}
|
|
132
|
+
// Ensure inactive slots map to themselves
|
|
133
|
+
for (let i = size; i < maxSize; i++) {
|
|
134
|
+
permutation[i] = i;
|
|
85
135
|
}
|
|
86
|
-
return
|
|
136
|
+
return { permutation, turnSalt };
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Generates a deterministic permutation for a specific game turn
|
|
140
|
+
* @param gameId - ID of the game
|
|
141
|
+
* @param turn - Turn number
|
|
142
|
+
* @param size - Size of the permutation
|
|
143
|
+
* @param verifierAddress - Address of the verifier
|
|
144
|
+
* @returns The generated permutation, secret, and commitment
|
|
145
|
+
*/
|
|
146
|
+
generateDeterministicPermutation = async ({ gameId, turn, size = 15, verifierAddress, }) => {
|
|
147
|
+
// This is kept secret to generate witness
|
|
148
|
+
// Create deterministic seed from game parameters and GM's signature
|
|
149
|
+
const { permutation, turnSalt } = await this.getPermutation({ gameId, turn, size, verifierAddress });
|
|
150
|
+
// Generate commitment
|
|
151
|
+
const poseidon = await (0, circomlibjs_1.buildPoseidon)();
|
|
152
|
+
const PoseidonFirst = BigInt(poseidon.F.toObject(poseidon([permutation[0], permutation[1], permutation[2], permutation[3], permutation[4]])));
|
|
153
|
+
const PoseidonSecond = BigInt(poseidon.F.toObject(poseidon([PoseidonFirst, permutation[5], permutation[6], permutation[7], permutation[8], permutation[9]])));
|
|
154
|
+
const PoseidonThird = BigInt(poseidon.F.toObject(poseidon([PoseidonSecond, permutation[10], permutation[11], permutation[12], permutation[13], permutation[14]])));
|
|
155
|
+
const commitment = BigInt(poseidon.F.toObject(poseidon([PoseidonThird, turnSalt])));
|
|
156
|
+
return {
|
|
157
|
+
permutation,
|
|
158
|
+
secret: turnSalt,
|
|
159
|
+
commitment,
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Permutes an array based on a deterministic permutation
|
|
164
|
+
* @param array - Array to permute
|
|
165
|
+
* @param gameId - ID of the game
|
|
166
|
+
* @param turn - Turn number
|
|
167
|
+
* @param verifierAddress - Address of the verifier
|
|
168
|
+
* @returns The permuted array
|
|
169
|
+
*/
|
|
170
|
+
permuteArray = async ({ array, gameId, turn, verifierAddress, }) => {
|
|
171
|
+
const { permutation } = await this.getPermutation({ gameId, turn, size: array.length, verifierAddress });
|
|
172
|
+
return (0, permutations_1.permuteArray)({ array, permutation });
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Reverses a permutation of an array
|
|
176
|
+
* @param permutedArray - Array to reverse
|
|
177
|
+
* @param gameId - ID of the game
|
|
178
|
+
* @param turn - Turn number
|
|
179
|
+
* @param verifierAddress - Address of the verifier
|
|
180
|
+
* @returns The original array
|
|
181
|
+
*/
|
|
182
|
+
reversePermutation = async ({ permutedArray, gameId, turn, verifierAddress, }) => {
|
|
183
|
+
const { permutation } = await this.getPermutation({ gameId, turn, size: permutedArray.length, verifierAddress });
|
|
184
|
+
return (0, permutations_1.reversePermutation)({ array: permutedArray, permutation });
|
|
87
185
|
};
|
|
88
186
|
/**
|
|
89
187
|
* Generates a salt for a specific game turn
|
|
90
188
|
* @param gameId - ID of the game
|
|
91
189
|
* @param turn - Turn number
|
|
190
|
+
* @param verifierAddress - Address of the verifier
|
|
92
191
|
* @returns Generated salt as Hex
|
|
93
192
|
*/
|
|
94
|
-
getTurnSalt = async ({ gameId, turn }) => {
|
|
95
|
-
|
|
193
|
+
getTurnSalt = async ({ gameId, turn, verifierAddress, }) => {
|
|
194
|
+
const gameKey = await this.gameKey({ gameId, contractAddress: verifierAddress });
|
|
195
|
+
const instance = new InstanceBase_1.default({
|
|
196
|
+
instanceAddress: verifierAddress,
|
|
197
|
+
publicClient: this.publicClient,
|
|
198
|
+
chainId: this.chainId,
|
|
199
|
+
});
|
|
200
|
+
const seed = instance.pkdf({
|
|
201
|
+
privateKey: gameKey,
|
|
202
|
+
turn,
|
|
203
|
+
gameId,
|
|
204
|
+
contractAddress: verifierAddress,
|
|
205
|
+
chainId: this.chainId,
|
|
206
|
+
scope: "turnSalt",
|
|
207
|
+
});
|
|
208
|
+
return BigInt(seed);
|
|
96
209
|
};
|
|
97
210
|
/**
|
|
98
211
|
* Generates a salt for a specific player in a game turn
|
|
99
212
|
* @param gameId - ID of the game
|
|
100
213
|
* @param turn - Turn number
|
|
101
|
-
* @param
|
|
214
|
+
* @param player - Address of the player
|
|
215
|
+
* @param verifierAddress - Address of the verifier
|
|
216
|
+
* @param size - Size of the permutation
|
|
102
217
|
* @returns Generated salt as Hex
|
|
103
218
|
*/
|
|
104
|
-
getTurnPlayersSalt = async ({ gameId, turn,
|
|
105
|
-
|
|
219
|
+
getTurnPlayersSalt = async ({ gameId, turn, player, verifierAddress, size, }) => {
|
|
220
|
+
(0, log_1.logger)(`Generating vote salt for player ${player} in game ${gameId}, turn ${turn}`);
|
|
221
|
+
const result = await this.generateDeterministicPermutation({
|
|
222
|
+
gameId,
|
|
223
|
+
turn: turn - 1n,
|
|
224
|
+
verifierAddress,
|
|
225
|
+
size,
|
|
226
|
+
}).then((perm) => {
|
|
227
|
+
return (0, viem_1.keccak256)((0, viem_1.encodePacked)(["address", "uint256"], [player, perm.secret]));
|
|
228
|
+
});
|
|
229
|
+
(0, log_1.logger)(`Generated vote salt for player ${player}`);
|
|
230
|
+
return result;
|
|
231
|
+
};
|
|
232
|
+
getProposalsVotedUpon = async ({ instanceAddress, gameId, turn, }) => {
|
|
233
|
+
const oldProposals = [];
|
|
234
|
+
//Proposals sequence is directly corresponding to proposers sequence
|
|
235
|
+
if (turn != 1n) {
|
|
236
|
+
const endedEvents = await this.publicClient.getContractEvents({
|
|
237
|
+
address: instanceAddress,
|
|
238
|
+
abi: abis_1.RankifyDiamondInstanceAbi,
|
|
239
|
+
eventName: "TurnEnded",
|
|
240
|
+
args: { gameId, turn: turn - 1n },
|
|
241
|
+
fromBlock: 0n,
|
|
242
|
+
});
|
|
243
|
+
const evt = endedEvents[0];
|
|
244
|
+
if (endedEvents.length > 1)
|
|
245
|
+
throw new Error("Multiple turns ended");
|
|
246
|
+
const args = evt.args;
|
|
247
|
+
const decryptedProposals = await this.decryptProposals({ instanceAddress, gameId, turn: turn - 1n });
|
|
248
|
+
if (args.newProposals) {
|
|
249
|
+
args.newProposals.slice(0, args?.players?.length).forEach((proposal, idx) => {
|
|
250
|
+
if (proposal !== "") {
|
|
251
|
+
const proposer = decryptedProposals.find((p) => p.proposal === proposal)?.proposer;
|
|
252
|
+
if (!proposer)
|
|
253
|
+
throw new Error("No proposer found for proposal");
|
|
254
|
+
oldProposals[idx] = {
|
|
255
|
+
proposer,
|
|
256
|
+
proposal: proposal,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
const _players = await this.publicClient.readContract({
|
|
263
|
+
address: instanceAddress,
|
|
264
|
+
abi: abis_1.RankifyDiamondInstanceAbi,
|
|
265
|
+
functionName: "getPlayers",
|
|
266
|
+
args: [gameId],
|
|
267
|
+
});
|
|
268
|
+
// Boundary case if no-one proposed a thing
|
|
269
|
+
_players.forEach((p, idx) => {
|
|
270
|
+
oldProposals[idx] = {
|
|
271
|
+
proposer: p,
|
|
272
|
+
proposal: "",
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return oldProposals;
|
|
106
278
|
};
|
|
107
279
|
/**
|
|
108
280
|
* Finds the index of a player's ongoing proposal
|
|
@@ -110,16 +282,113 @@ class GameMaster {
|
|
|
110
282
|
* @param player - Address of the player
|
|
111
283
|
* @returns Index of the player's proposal, -1 if not found
|
|
112
284
|
*/
|
|
113
|
-
findPlayerOngoingProposalIndex = async ({ instanceAddress, gameId, player, }) => {
|
|
285
|
+
findPlayerOngoingProposalIndex = async ({ instanceAddress, gameId, player, turn, }) => {
|
|
114
286
|
const baseInstance = new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
115
|
-
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
|
|
287
|
+
let currentTurn = 0n;
|
|
288
|
+
if (!turn) {
|
|
289
|
+
const r = await baseInstance.getOngoingProposals(gameId);
|
|
290
|
+
currentTurn = r.currentTurn;
|
|
291
|
+
if (currentTurn == 0n) {
|
|
292
|
+
console.error("No proposals in turn 0");
|
|
293
|
+
return -1;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
currentTurn = turn;
|
|
119
298
|
}
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
299
|
+
const proposalsVotedUpon = await this.getProposalsVotedUpon({ instanceAddress, gameId, turn: currentTurn });
|
|
300
|
+
return proposalsVotedUpon.findIndex((p) => p.proposer === player);
|
|
301
|
+
};
|
|
302
|
+
validateJoinGame = async (props) => {
|
|
303
|
+
const { gameId, participant, instanceAddress } = props;
|
|
304
|
+
try {
|
|
305
|
+
const baseInstance = new InstanceBase_1.default({
|
|
306
|
+
instanceAddress,
|
|
307
|
+
publicClient: this.publicClient,
|
|
308
|
+
chainId: this.chainId,
|
|
309
|
+
});
|
|
310
|
+
const gameState = await baseInstance.getGameStateDetails(gameId);
|
|
311
|
+
if (gameState.gamePhase !== types_1.gameStatusEnum.open) {
|
|
312
|
+
return { result: false, errorMessage: "Game is not open for registration" };
|
|
313
|
+
}
|
|
314
|
+
if (gameState.players.length === Number(gameState.maxPlayerCnt)) {
|
|
315
|
+
return { result: false, errorMessage: "Game is already full" };
|
|
316
|
+
}
|
|
317
|
+
if (gameState.players.indexOf(participant) !== -1) {
|
|
318
|
+
return { result: false, errorMessage: "Player already registered" };
|
|
319
|
+
}
|
|
320
|
+
return { result: true, errorMessage: "" };
|
|
321
|
+
}
|
|
322
|
+
catch (e) {
|
|
323
|
+
throw await (0, utils_1.handleRPCError)(e);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
/**
|
|
327
|
+
* Signs a joining game event
|
|
328
|
+
* @param gameId - ID of the game
|
|
329
|
+
* @param participant - Address of the participant
|
|
330
|
+
* @param instanceAddress - Address of the game instance
|
|
331
|
+
* @returns Signature and gmCommitment
|
|
332
|
+
*/
|
|
333
|
+
signJoiningGame = async (props, timeToJoin = 60 * 10) => {
|
|
334
|
+
if (!this.walletClient.account)
|
|
335
|
+
throw new Error("No account");
|
|
336
|
+
(0, log_1.logger)(`Signing joining game..`);
|
|
337
|
+
const { gameId, participant, instanceAddress, participantPubKeyHash } = props;
|
|
338
|
+
const baseInstance = new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
339
|
+
const eip712 = await baseInstance.getEIP712Domain();
|
|
340
|
+
(0, log_1.logger)({
|
|
341
|
+
gameId: props.gameId,
|
|
342
|
+
participant: props.participant,
|
|
343
|
+
instanceAddress: props.instanceAddress,
|
|
344
|
+
chainId: this.chainId,
|
|
345
|
+
name: eip712.name,
|
|
346
|
+
version: eip712.version,
|
|
347
|
+
gameMaster: this.walletClient.account?.address,
|
|
348
|
+
participantPubKeyHash,
|
|
349
|
+
}, 2);
|
|
350
|
+
const deadline = BigInt(Math.floor(Date.now() / 1000) + timeToJoin);
|
|
351
|
+
//ToDo This is placeholder for now, we will need it later in staking
|
|
352
|
+
const gmCommitment = (0, viem_1.stringToHex)("0x123131231311", { size: 32 });
|
|
353
|
+
console.log({
|
|
354
|
+
name: eip712.name,
|
|
355
|
+
version: eip712.version,
|
|
356
|
+
chainId: this.chainId,
|
|
357
|
+
verifyingContract: instanceAddress,
|
|
358
|
+
}, {
|
|
359
|
+
participant,
|
|
360
|
+
gameId,
|
|
361
|
+
gmCommitment,
|
|
362
|
+
deadline,
|
|
363
|
+
participantPubKeyHash,
|
|
364
|
+
});
|
|
365
|
+
const signature = await this.walletClient.signTypedData({
|
|
366
|
+
domain: {
|
|
367
|
+
name: eip712.name,
|
|
368
|
+
version: eip712.version,
|
|
369
|
+
chainId: this.chainId,
|
|
370
|
+
verifyingContract: instanceAddress,
|
|
371
|
+
},
|
|
372
|
+
types: {
|
|
373
|
+
AttestJoiningGame: [
|
|
374
|
+
{ type: "address", name: "participant" },
|
|
375
|
+
{ type: "uint256", name: "gameId" },
|
|
376
|
+
{ type: "bytes32", name: "gmCommitment" },
|
|
377
|
+
{ type: "uint256", name: "deadline" },
|
|
378
|
+
{ type: "bytes32", name: "participantPubKeyHash" },
|
|
379
|
+
],
|
|
380
|
+
},
|
|
381
|
+
message: {
|
|
382
|
+
participant,
|
|
383
|
+
gameId,
|
|
384
|
+
gmCommitment,
|
|
385
|
+
deadline,
|
|
386
|
+
participantPubKeyHash,
|
|
387
|
+
},
|
|
388
|
+
primaryType: "AttestJoiningGame",
|
|
389
|
+
account: this.walletClient.account,
|
|
390
|
+
});
|
|
391
|
+
return { signature, gmCommitment, deadline };
|
|
123
392
|
};
|
|
124
393
|
/**
|
|
125
394
|
* Submits a vote for proposals
|
|
@@ -128,7 +397,7 @@ class GameMaster {
|
|
|
128
397
|
* @param voter - Address of the voter
|
|
129
398
|
* @returns Transaction hash
|
|
130
399
|
*/
|
|
131
|
-
submitVote = async ({ instanceAddress, gameId, vote, voter, }) => {
|
|
400
|
+
submitVote = async ({ instanceAddress, gameId, vote, voter, voterSignature, ballotHash, ballotId, }) => {
|
|
132
401
|
if (!gameId)
|
|
133
402
|
throw new Error("No gameId");
|
|
134
403
|
if (!vote)
|
|
@@ -136,9 +405,10 @@ class GameMaster {
|
|
|
136
405
|
if (!voter)
|
|
137
406
|
throw new Error("No voter");
|
|
138
407
|
const proposerIdx = await this.findPlayerOngoingProposalIndex({ instanceAddress, gameId, player: voter });
|
|
139
|
-
if (proposerIdx
|
|
408
|
+
if (proposerIdx == -1)
|
|
409
|
+
throw new Error("You are not a proposer in this game");
|
|
410
|
+
if (vote[proposerIdx] !== 0n)
|
|
140
411
|
throw new Error("You cannot vote for your own proposal");
|
|
141
|
-
const votesHidden = await this.encryptionCallback(JSON.stringify(vote.map((vi) => vi.toString())));
|
|
142
412
|
if (!this.walletClient?.account?.address)
|
|
143
413
|
throw new Error("No account address found");
|
|
144
414
|
try {
|
|
@@ -147,7 +417,7 @@ class GameMaster {
|
|
|
147
417
|
address: instanceAddress,
|
|
148
418
|
abi: abis_1.RankifyDiamondInstanceAbi,
|
|
149
419
|
functionName: "submitVote",
|
|
150
|
-
args: [gameId,
|
|
420
|
+
args: [gameId, ballotId, voter, viem_1.zeroHash, voterSignature, ballotHash],
|
|
151
421
|
});
|
|
152
422
|
return this.walletClient.writeContract(request);
|
|
153
423
|
}
|
|
@@ -156,14 +426,137 @@ class GameMaster {
|
|
|
156
426
|
}
|
|
157
427
|
};
|
|
158
428
|
/**
|
|
159
|
-
*
|
|
429
|
+
* Types for proposal submission
|
|
430
|
+
*/
|
|
431
|
+
proposalTypes = {
|
|
432
|
+
SubmitProposal: [
|
|
433
|
+
{ type: "uint256", name: "gameId" },
|
|
434
|
+
{ type: "address", name: "proposer" },
|
|
435
|
+
{ type: "string", name: "encryptedProposal" },
|
|
436
|
+
{ type: "uint256", name: "commitment" },
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
signProposal = async ({ verifierAddress, proposer, gameId, encryptedProposal, commitment, eip712, }) => {
|
|
440
|
+
// Generate typed data hash matching Solidity's keccak256(abi.encode(...))
|
|
441
|
+
if (!this.walletClient.account)
|
|
442
|
+
throw new Error("No account");
|
|
443
|
+
return this.walletClient.signTypedData({
|
|
444
|
+
domain: {
|
|
445
|
+
name: eip712.name,
|
|
446
|
+
version: eip712.version,
|
|
447
|
+
chainId: this.chainId,
|
|
448
|
+
verifyingContract: verifierAddress,
|
|
449
|
+
},
|
|
450
|
+
types: this.proposalTypes,
|
|
451
|
+
message: {
|
|
452
|
+
gameId,
|
|
453
|
+
proposer,
|
|
454
|
+
encryptedProposal,
|
|
455
|
+
commitment,
|
|
456
|
+
},
|
|
457
|
+
primaryType: "SubmitProposal",
|
|
458
|
+
account: this.walletClient.account,
|
|
459
|
+
});
|
|
460
|
+
};
|
|
461
|
+
proposalValues = async ({ instanceAddress, gameId, proposal, proposer, turn, }) => {
|
|
462
|
+
const instance = new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
463
|
+
const proposerPubKey = await instance.getPlayerPubKey({
|
|
464
|
+
instanceAddress,
|
|
465
|
+
gameId,
|
|
466
|
+
player: proposer,
|
|
467
|
+
});
|
|
468
|
+
const sharedKey = instance.sharedSigner({
|
|
469
|
+
publicKey: proposerPubKey,
|
|
470
|
+
privateKey: await this.gameKey({ gameId, contractAddress: instanceAddress }),
|
|
471
|
+
gameId,
|
|
472
|
+
turn,
|
|
473
|
+
contractAddress: instanceAddress,
|
|
474
|
+
chainId: this.chainId,
|
|
475
|
+
});
|
|
476
|
+
// const poseidon = await buildPoseidon();
|
|
477
|
+
const proposalValue = BigInt((0, viem_1.keccak256)((0, viem_1.encodePacked)(["string"], [proposal])));
|
|
478
|
+
const randomnessValue = BigInt((0, viem_1.keccak256)((0, viem_1.encodePacked)(["string"], [sharedKey])));
|
|
479
|
+
// Calculate commitment using poseidon
|
|
480
|
+
return {
|
|
481
|
+
proposalValue,
|
|
482
|
+
randomnessValue,
|
|
483
|
+
proposal,
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
/**
|
|
487
|
+
* Encrypts a proposal
|
|
488
|
+
* @param proposal - Proposal to encrypt
|
|
489
|
+
* @param turn - Turn number
|
|
490
|
+
* @param instanceAddress - Address of the game instance
|
|
491
|
+
* @param gameId - ID of the game
|
|
492
|
+
* @param proposerPubKey - Public key of the proposer
|
|
493
|
+
* @returns Encrypted proposal and shared key
|
|
494
|
+
*/
|
|
495
|
+
encryptProposal = async ({ proposal, turn, instanceAddress, gameId, proposerPubKey, }) => {
|
|
496
|
+
const instance = new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
497
|
+
const sharedKey = instance.sharedSigner({
|
|
498
|
+
publicKey: proposerPubKey,
|
|
499
|
+
privateKey: await this.gameKey({ gameId, contractAddress: instanceAddress }),
|
|
500
|
+
gameId,
|
|
501
|
+
turn,
|
|
502
|
+
contractAddress: instanceAddress,
|
|
503
|
+
chainId: this.chainId,
|
|
504
|
+
});
|
|
505
|
+
(0, log_1.logger)(`Encrypting proposal ${proposal} with shared key (hashed value: ${(0, viem_1.keccak256)(sharedKey)})`);
|
|
506
|
+
const encryptedProposal = aes_1.default.encrypt(proposal, sharedKey).toString();
|
|
507
|
+
(0, log_1.logger)(`Encrypted proposal ${encryptedProposal}`);
|
|
508
|
+
return { encryptedProposal, sharedKey };
|
|
509
|
+
};
|
|
510
|
+
/**
|
|
511
|
+
* Attests a proposal
|
|
512
|
+
* @param instanceAddress - Address of the game instance
|
|
160
513
|
* @param gameId - ID of the game
|
|
514
|
+
* @param proposal - Proposal to attest
|
|
515
|
+
* @param proposerPubKey - Public key of the proposer
|
|
161
516
|
* @param turn - Turn number
|
|
162
|
-
* @
|
|
163
|
-
* @returns Hidden proposer hash
|
|
517
|
+
* @returns The attested proposal
|
|
164
518
|
*/
|
|
165
|
-
|
|
166
|
-
|
|
519
|
+
attestProposal = async ({ instanceAddress, gameId, proposal, proposerPubKey, turn, }) => {
|
|
520
|
+
const proposerAddress = (0, accounts_1.publicKeyToAddress)(proposerPubKey);
|
|
521
|
+
(0, log_1.logger)(`Creating proposal secrets for player ${proposerAddress} in game ${gameId}`);
|
|
522
|
+
const poseidon = await (0, circomlibjs_1.buildPoseidon)();
|
|
523
|
+
const instance = new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
524
|
+
const { encryptedProposal, sharedKey } = await this.encryptProposal({
|
|
525
|
+
proposal,
|
|
526
|
+
turn,
|
|
527
|
+
instanceAddress,
|
|
528
|
+
gameId,
|
|
529
|
+
proposerPubKey,
|
|
530
|
+
});
|
|
531
|
+
const proposalValue = BigInt((0, viem_1.keccak256)((0, viem_1.encodePacked)(["string"], [proposal])));
|
|
532
|
+
const randomnessValue = BigInt((0, viem_1.keccak256)((0, viem_1.encodePacked)(["string"], [sharedKey])));
|
|
533
|
+
// Calculate commitment using poseidon
|
|
534
|
+
const hash = poseidon([proposalValue, randomnessValue]);
|
|
535
|
+
const poseidonCommitment = BigInt(poseidon.F.toObject(hash));
|
|
536
|
+
const eip712 = await instance.getEIP712Domain();
|
|
537
|
+
const signature = await this.signProposal({
|
|
538
|
+
verifierAddress: instanceAddress,
|
|
539
|
+
proposer: proposerAddress,
|
|
540
|
+
gameId,
|
|
541
|
+
encryptedProposal,
|
|
542
|
+
commitment: poseidonCommitment,
|
|
543
|
+
eip712,
|
|
544
|
+
});
|
|
545
|
+
const params = {
|
|
546
|
+
gameId,
|
|
547
|
+
encryptedProposal,
|
|
548
|
+
commitment: poseidonCommitment,
|
|
549
|
+
proposer: proposerAddress,
|
|
550
|
+
gmSignature: signature,
|
|
551
|
+
};
|
|
552
|
+
(0, log_1.logger)(`Generated proposal secrets with commitment ${poseidonCommitment}`);
|
|
553
|
+
return {
|
|
554
|
+
submissionParams: params,
|
|
555
|
+
proposal,
|
|
556
|
+
proposerAddress,
|
|
557
|
+
proposalValue,
|
|
558
|
+
randomnessValue,
|
|
559
|
+
};
|
|
167
560
|
};
|
|
168
561
|
/**
|
|
169
562
|
* Submits a proposal to the game
|
|
@@ -173,18 +566,22 @@ class GameMaster {
|
|
|
173
566
|
* @param proposer - Address of the proposer
|
|
174
567
|
* @returns Transaction hash
|
|
175
568
|
*/
|
|
176
|
-
submitProposal = async ({ instanceAddress,
|
|
569
|
+
submitProposal = async ({ instanceAddress, submissionParams, proposerSignature, }) => {
|
|
177
570
|
// let proposalData: GetAbiItemParameters<typeof RankifyDiamondInstanceAbi, "submitProposal">["args"];
|
|
178
571
|
// proposalData[0].
|
|
179
|
-
const
|
|
180
|
-
|
|
572
|
+
const txParams = [
|
|
573
|
+
{
|
|
574
|
+
...submissionParams,
|
|
575
|
+
proposerSignature,
|
|
576
|
+
},
|
|
577
|
+
];
|
|
181
578
|
try {
|
|
182
579
|
const { request } = await this.publicClient.simulateContract({
|
|
183
580
|
account: this.walletClient.account,
|
|
184
581
|
address: instanceAddress,
|
|
185
582
|
abi: abis_1.RankifyDiamondInstanceAbi,
|
|
186
583
|
functionName: "submitProposal",
|
|
187
|
-
args:
|
|
584
|
+
args: txParams,
|
|
188
585
|
});
|
|
189
586
|
return this.walletClient.writeContract(request);
|
|
190
587
|
}
|
|
@@ -205,18 +602,28 @@ class GameMaster {
|
|
|
205
602
|
eventName: "VoteSubmitted",
|
|
206
603
|
args: { gameId, turn },
|
|
207
604
|
});
|
|
208
|
-
|
|
605
|
+
(0, log_1.logger)(`Found ${evts.length} events`);
|
|
606
|
+
if (evts.length === 0)
|
|
607
|
+
return [];
|
|
608
|
+
// Process events one by one to allow errors to propagate
|
|
609
|
+
const votes = [];
|
|
610
|
+
for (const event of evts) {
|
|
209
611
|
if (!event.args.player)
|
|
210
|
-
throw new Error("No player
|
|
211
|
-
if (!event.args.
|
|
212
|
-
throw new Error("No
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
612
|
+
throw new Error("No player in event");
|
|
613
|
+
if (!event.args.sealedBallotId)
|
|
614
|
+
throw new Error("No sealedBallotId in event");
|
|
615
|
+
const turnKey = await this.calculateSharedTurnKey({
|
|
616
|
+
instanceAddress,
|
|
617
|
+
gameId,
|
|
618
|
+
turn,
|
|
216
619
|
player: event.args.player,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
620
|
+
});
|
|
621
|
+
const decryptedVotes = await this.decryptVote(event.args.sealedBallotId, turnKey);
|
|
622
|
+
votes.push({
|
|
623
|
+
player: event.args.player,
|
|
624
|
+
votes: decryptedVotes,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
220
627
|
return votes;
|
|
221
628
|
};
|
|
222
629
|
/**
|
|
@@ -309,81 +716,50 @@ class GameMaster {
|
|
|
309
716
|
if (!Array.isArray(players)) {
|
|
310
717
|
throw new Error("Expected players to be an array");
|
|
311
718
|
}
|
|
312
|
-
const oldProposals = [];
|
|
313
719
|
const proposerIndices = [];
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const evt = endedEvents[0];
|
|
324
|
-
if (endedEvents.length > 1)
|
|
325
|
-
throw new Error("Multiple turns ended");
|
|
326
|
-
const args = evt.args;
|
|
327
|
-
const decryptedProposals = await this.decryptProposals({ instanceAddress, gameId, turn: turn - 1n });
|
|
328
|
-
if (args.newProposals) {
|
|
329
|
-
args.newProposals.forEach((proposal, idx) => {
|
|
330
|
-
const proposer = decryptedProposals.find((p) => p.proposal === proposal)?.proposer;
|
|
331
|
-
if (!proposer)
|
|
332
|
-
throw new Error("No proposer found for proposal");
|
|
333
|
-
oldProposals[idx] = {
|
|
334
|
-
proposer,
|
|
335
|
-
proposal: proposal,
|
|
336
|
-
};
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
// Boundary case if no-one proposed a thing
|
|
341
|
-
players.forEach((p, idx) => {
|
|
342
|
-
oldProposals[idx] = {
|
|
343
|
-
proposer: p,
|
|
344
|
-
proposal: "",
|
|
345
|
-
};
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
votes = await this.decryptTurnVotes({ instanceAddress, gameId, turn }).then((voteSubmissions) => {
|
|
349
|
-
const orderedVotes = players.map((player) => ({
|
|
350
|
-
player,
|
|
351
|
-
votes: new Array(players.length).fill(0n),
|
|
352
|
-
}));
|
|
353
|
-
players.forEach((player, playerIdx) => {
|
|
354
|
-
const vote = voteSubmissions.find((v) => v.player === player);
|
|
355
|
-
if (vote)
|
|
356
|
-
orderedVotes[playerIdx] = vote;
|
|
357
|
-
else
|
|
358
|
-
orderedVotes[playerIdx] = {
|
|
359
|
-
player,
|
|
360
|
-
votes: new Array(players.length).fill(0n),
|
|
361
|
-
};
|
|
362
|
-
});
|
|
363
|
-
return orderedVotes;
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
const newProposals = await this.decryptProposals({ instanceAddress, gameId, turn });
|
|
720
|
+
const oldProposals = await this.getProposalsVotedUpon({ instanceAddress, gameId, turn });
|
|
721
|
+
const decryptedProposals = await this.decryptProposals({ instanceAddress, gameId, turn });
|
|
722
|
+
const proposals = players.map((player) => {
|
|
723
|
+
const proposal = decryptedProposals.find((p) => p.proposer === player)?.proposal ?? "";
|
|
724
|
+
return {
|
|
725
|
+
proposer: player,
|
|
726
|
+
proposal,
|
|
727
|
+
};
|
|
728
|
+
});
|
|
367
729
|
players.forEach((player) => {
|
|
368
730
|
let proposerIdx = oldProposals.findIndex((p) => player === p.proposer);
|
|
369
731
|
if (proposerIdx === -1)
|
|
370
732
|
proposerIdx = players.length; //Did not propose
|
|
371
733
|
proposerIndices.push(BigInt(proposerIdx));
|
|
372
734
|
});
|
|
735
|
+
const voteDecrypted = await this.decryptTurnVotes({ instanceAddress, gameId, turn });
|
|
736
|
+
const votes = await Promise.all(players.map(async (player) => {
|
|
737
|
+
const vote = voteDecrypted.find((v) => v.player === player);
|
|
738
|
+
if (!vote?.votes)
|
|
739
|
+
return players.map(() => 0n);
|
|
740
|
+
return vote.votes;
|
|
741
|
+
}));
|
|
373
742
|
const tableData = players.map((player, idx) => ({
|
|
374
743
|
player,
|
|
375
744
|
proposerIndex: proposerIndices[idx],
|
|
376
745
|
proposer: oldProposals[Number(proposerIndices[idx])].proposer,
|
|
377
746
|
}));
|
|
378
747
|
console.table(tableData);
|
|
379
|
-
const
|
|
380
|
-
|
|
748
|
+
const attested = await this.getProposalsIntegrity({
|
|
749
|
+
gameId,
|
|
750
|
+
turn,
|
|
751
|
+
verifierAddress: instanceAddress,
|
|
752
|
+
size: players.length,
|
|
753
|
+
proposals,
|
|
754
|
+
});
|
|
755
|
+
(0, log_1.logger)(`votes:`);
|
|
756
|
+
(0, log_1.logger)(votes);
|
|
381
757
|
const { request } = await this.publicClient.simulateContract({
|
|
382
758
|
abi: abis_1.RankifyDiamondInstanceAbi,
|
|
383
759
|
account: this.walletClient.account,
|
|
384
760
|
address: instanceAddress,
|
|
385
761
|
functionName: "endTurn",
|
|
386
|
-
args: [gameId, votes
|
|
762
|
+
args: [gameId, votes, attested.newProposals, attested.permutation, attested.nullifier],
|
|
387
763
|
});
|
|
388
764
|
return this.walletClient.writeContract(request);
|
|
389
765
|
}
|
|
@@ -391,6 +767,302 @@ class GameMaster {
|
|
|
391
767
|
throw await (0, utils_1.handleRPCError)(e);
|
|
392
768
|
}
|
|
393
769
|
};
|
|
770
|
+
gameKey = async ({ gameId, contractAddress }) => {
|
|
771
|
+
(0, log_1.logger)(`Signing game key for game ${gameId} at address ${contractAddress}`);
|
|
772
|
+
const message = (0, viem_1.encodePacked)(["uint256", "address", "string"], [gameId, contractAddress, "gameKey"]);
|
|
773
|
+
(0, log_1.logger)(`Signing message: ${message}`, 2);
|
|
774
|
+
if (!this.walletClient.account)
|
|
775
|
+
throw new Error("No account");
|
|
776
|
+
const gameKey = await this.walletClient
|
|
777
|
+
.signMessage({
|
|
778
|
+
message,
|
|
779
|
+
account: this.walletClient.account,
|
|
780
|
+
})
|
|
781
|
+
.then((sig) => (0, viem_1.keccak256)(sig));
|
|
782
|
+
(0, log_1.logger)(`Game key: ${gameKey}`, 2);
|
|
783
|
+
return gameKey;
|
|
784
|
+
};
|
|
785
|
+
calculateSharedTurnKey = async ({ instanceAddress, gameId, turn, player, }) => {
|
|
786
|
+
(0, log_1.logger)(`Calculating shared turn key for player ${player} in game ${gameId} at address ${instanceAddress}`);
|
|
787
|
+
const instance = new InstanceBase_1.default({ instanceAddress, publicClient: this.publicClient, chainId: this.chainId });
|
|
788
|
+
const playerPubKey = await instance.getPlayerPubKey({ instanceAddress, gameId, player });
|
|
789
|
+
(0, log_1.logger)(`Player public key: ${playerPubKey}`, 2);
|
|
790
|
+
return instance.sharedSigner({
|
|
791
|
+
publicKey: playerPubKey,
|
|
792
|
+
privateKey: await this.gameKey({ gameId, contractAddress: instanceAddress }),
|
|
793
|
+
gameId,
|
|
794
|
+
turn,
|
|
795
|
+
contractAddress: instanceAddress,
|
|
796
|
+
chainId: this.chainId,
|
|
797
|
+
});
|
|
798
|
+
};
|
|
799
|
+
decryptVote = async (vote, privateKey) => {
|
|
800
|
+
const decrypted = aes_1.default.decrypt(vote, privateKey).toString(crypto_js_1.default.enc.Utf8);
|
|
801
|
+
if (!decrypted) {
|
|
802
|
+
throw new Error("Failed to decrypt vote");
|
|
803
|
+
}
|
|
804
|
+
try {
|
|
805
|
+
const parsed = JSON.parse(decrypted);
|
|
806
|
+
(0, log_1.logger)(`Decrypted vote:`, 2);
|
|
807
|
+
(0, log_1.logger)(parsed, 2);
|
|
808
|
+
return parsed.map((v) => BigInt(v));
|
|
809
|
+
// eslint-disable-next-line
|
|
810
|
+
}
|
|
811
|
+
catch (e) {
|
|
812
|
+
throw new Error("Unexpected token");
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
/**
|
|
816
|
+
* Creates and signs a vote for testing purposes
|
|
817
|
+
* @param params - Parameters including voter, game info, and vote configuration
|
|
818
|
+
* @returns A complete mock vote with signatures
|
|
819
|
+
*/
|
|
820
|
+
attestVote = async ({ voter, gameId, turn, vote, verifierAddress, }) => {
|
|
821
|
+
(0, log_1.logger)(`Attesting vote for player ${voter} in game ${gameId}, turn ${turn}`);
|
|
822
|
+
const gameSize = (await this.getPlayers({ instanceAddress: verifierAddress, gameId })).length;
|
|
823
|
+
const instance = new InstanceBase_1.default({
|
|
824
|
+
instanceAddress: verifierAddress,
|
|
825
|
+
publicClient: this.publicClient,
|
|
826
|
+
chainId: this.chainId,
|
|
827
|
+
});
|
|
828
|
+
const eip712 = await instance.getEIP712Domain();
|
|
829
|
+
const playerSalt = await this.getTurnPlayersSalt({
|
|
830
|
+
gameId,
|
|
831
|
+
turn,
|
|
832
|
+
player: voter,
|
|
833
|
+
verifierAddress,
|
|
834
|
+
size: gameSize,
|
|
835
|
+
});
|
|
836
|
+
const ballot = {
|
|
837
|
+
vote: vote,
|
|
838
|
+
salt: playerSalt,
|
|
839
|
+
};
|
|
840
|
+
const ballotHash = (0, viem_1.keccak256)((0, viem_1.encodePacked)(["uint256[]", "bytes32"], [vote, playerSalt]));
|
|
841
|
+
const turnKey = await this.calculateSharedTurnKey({
|
|
842
|
+
instanceAddress: verifierAddress,
|
|
843
|
+
gameId,
|
|
844
|
+
turn,
|
|
845
|
+
player: voter,
|
|
846
|
+
});
|
|
847
|
+
const ballotId = aes_1.default.encrypt(JSON.stringify(ballot.vote.map((v) => v.toString())), turnKey).toString();
|
|
848
|
+
const gmSignature = await this.signVote({
|
|
849
|
+
verifierAddress,
|
|
850
|
+
voter,
|
|
851
|
+
gameId,
|
|
852
|
+
sealedBallotId: ballotId,
|
|
853
|
+
ballotHash,
|
|
854
|
+
name: eip712.name,
|
|
855
|
+
version: eip712.version,
|
|
856
|
+
});
|
|
857
|
+
(0, log_1.logger)(`Vote attested for player ${voter} by ${this.walletClient.account?.address}`);
|
|
858
|
+
(0, log_1.logger)({
|
|
859
|
+
gameId,
|
|
860
|
+
turn,
|
|
861
|
+
vote,
|
|
862
|
+
verifierAddress,
|
|
863
|
+
gameSize,
|
|
864
|
+
name: eip712.name,
|
|
865
|
+
version: eip712.version,
|
|
866
|
+
chainId: this.chainId,
|
|
867
|
+
}, 2);
|
|
868
|
+
return { vote, ballotHash, ballot, ballotId, gmSignature };
|
|
869
|
+
};
|
|
870
|
+
/**
|
|
871
|
+
* Signs a vote
|
|
872
|
+
* @param params - Parameters including voter, game info, and vote configuration
|
|
873
|
+
* @returns The signed vote
|
|
874
|
+
*/
|
|
875
|
+
signVote = async (params) => {
|
|
876
|
+
const { voter, gameId, verifierAddress, sealedBallotId, ballotHash, name, version } = params;
|
|
877
|
+
(0, log_1.logger)(`Signing vote for player ${voter} in game ${gameId}`);
|
|
878
|
+
const types = {
|
|
879
|
+
SubmitVote: [
|
|
880
|
+
{ name: "gameId", type: "uint256" },
|
|
881
|
+
{ name: "voter", type: "address" },
|
|
882
|
+
{ name: "sealedBallotId", type: "string" },
|
|
883
|
+
{ name: "ballotHash", type: "bytes32" },
|
|
884
|
+
],
|
|
885
|
+
};
|
|
886
|
+
if (!this.walletClient.account)
|
|
887
|
+
throw new Error("No account");
|
|
888
|
+
const signature = await this.walletClient.signTypedData({
|
|
889
|
+
domain: {
|
|
890
|
+
name,
|
|
891
|
+
version,
|
|
892
|
+
chainId: this.chainId,
|
|
893
|
+
verifyingContract: verifierAddress,
|
|
894
|
+
},
|
|
895
|
+
types,
|
|
896
|
+
primaryType: "SubmitVote",
|
|
897
|
+
message: {
|
|
898
|
+
gameId,
|
|
899
|
+
voter,
|
|
900
|
+
sealedBallotId,
|
|
901
|
+
ballotHash,
|
|
902
|
+
},
|
|
903
|
+
account: this.walletClient.account,
|
|
904
|
+
});
|
|
905
|
+
(0, log_1.logger)(`Vote signed for player ${voter}`);
|
|
906
|
+
return signature;
|
|
907
|
+
};
|
|
908
|
+
/**
|
|
909
|
+
* Generates integrity data for the end of a game turn
|
|
910
|
+
* @param params - Parameters including game info, turn, and proposal data
|
|
911
|
+
* @returns Integrity data including permutation, secret, and proof
|
|
912
|
+
*/
|
|
913
|
+
generateEndTurnIntegrity = async ({ gameId, turn, verifierAddress, size = 15, proposals, }) => {
|
|
914
|
+
const maxSize = 15;
|
|
915
|
+
const { permutation, secret: nullifier } = await this.generateDeterministicPermutation({
|
|
916
|
+
gameId,
|
|
917
|
+
turn: turn - 1n,
|
|
918
|
+
verifierAddress,
|
|
919
|
+
size,
|
|
920
|
+
});
|
|
921
|
+
const values = await Promise.all(proposals.map((p) => p.proposal === ""
|
|
922
|
+
? {
|
|
923
|
+
proposalValue: 0n,
|
|
924
|
+
randomnessValue: 0n,
|
|
925
|
+
proposer: p.proposer,
|
|
926
|
+
}
|
|
927
|
+
: this.proposalValues({
|
|
928
|
+
instanceAddress: verifierAddress,
|
|
929
|
+
gameId,
|
|
930
|
+
proposal: p.proposal,
|
|
931
|
+
turn,
|
|
932
|
+
proposer: p.proposer,
|
|
933
|
+
})));
|
|
934
|
+
const inputs = await this.createInputs({
|
|
935
|
+
numActive: size,
|
|
936
|
+
proposals: values.map((v) => v.proposalValue),
|
|
937
|
+
commitmentRandomnesses: values.map((v) => v.randomnessValue),
|
|
938
|
+
gameId,
|
|
939
|
+
turn,
|
|
940
|
+
verifierAddress,
|
|
941
|
+
});
|
|
942
|
+
(0, log_1.logger)(inputs, 2);
|
|
943
|
+
// Apply permutation to proposals array
|
|
944
|
+
const permutedProposals = [...proposals];
|
|
945
|
+
for (let i = 0; i < maxSize; i++) {
|
|
946
|
+
if (i < size) {
|
|
947
|
+
permutedProposals[Number(inputs.permutation[i])] = proposals[i];
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
const config = {
|
|
951
|
+
circuitName: "ProposalsIntegrity15",
|
|
952
|
+
// node_modules/rankify-contracts/zk_artifacts
|
|
953
|
+
circuitArtifactsPath: path_1.default.join(__dirname, "../../node_modules/rankify-contracts/zk_artifacts/circuits/proposals_integrity_15.circom/"),
|
|
954
|
+
verifierDirPath: path_1.default.join(__dirname, "../../node_modules/rankify-contracts/src/verifiers"),
|
|
955
|
+
};
|
|
956
|
+
const implementer = new zkit_1.Groth16Implementer();
|
|
957
|
+
const circuit = new zkit_1.CircuitZKit(config, implementer);
|
|
958
|
+
const proof = await circuit.generateProof(inputs);
|
|
959
|
+
const callData = await circuit.generateCalldata(proof);
|
|
960
|
+
// const circuit = await hre.zkit.getCircuit("ProposalsIntegrity15");
|
|
961
|
+
// const inputsKey = ethers.utils.solidityKeccak256(["string"], [JSON.stringify(inputs) + "groth16"]);
|
|
962
|
+
// let cached = loadFromCache(inputsKey);
|
|
963
|
+
// if (cached) {
|
|
964
|
+
// log(`Loaded proof from cache for inputsKey ${inputsKey}`, 2);
|
|
965
|
+
// } else {
|
|
966
|
+
// log(`Generating proof for inputsKey ${inputsKey}`, 2);
|
|
967
|
+
// const proof = await circuit.generateProof(inputs);
|
|
968
|
+
// saveToCache(inputsKey, proof);
|
|
969
|
+
// cached = proof;
|
|
970
|
+
// }
|
|
971
|
+
// const proof = "0x00";
|
|
972
|
+
if (!proof) {
|
|
973
|
+
throw new Error("Proof not found");
|
|
974
|
+
}
|
|
975
|
+
// const callData = await circuit.generateCalldata(proof);
|
|
976
|
+
const a = callData[0].map((a) => BigInt(a));
|
|
977
|
+
const b = callData[1].map((b) => b.map((b) => BigInt(b)));
|
|
978
|
+
const c = callData[2].map((c) => BigInt(c));
|
|
979
|
+
return {
|
|
980
|
+
commitment: inputs.permutationCommitment,
|
|
981
|
+
nullifier,
|
|
982
|
+
permutation: permutation.slice(0, size),
|
|
983
|
+
permutedProposals: permutedProposals.map((proposal) => proposal.proposal),
|
|
984
|
+
a,
|
|
985
|
+
b,
|
|
986
|
+
c,
|
|
987
|
+
};
|
|
988
|
+
};
|
|
989
|
+
/**
|
|
990
|
+
* Gets proposal integrity data for testing
|
|
991
|
+
* @param params - Parameters including game info and proposal data
|
|
992
|
+
* @returns Proposal integrity information including permutations and proofs
|
|
993
|
+
*/
|
|
994
|
+
async getProposalsIntegrity({ size, gameId, turn, proposals, verifierAddress, }) {
|
|
995
|
+
(0, log_1.logger)(`Generating proposals integrity for game ${gameId}, turn ${turn} with ${size} players.`);
|
|
996
|
+
const { commitment, nullifier, permutation, permutedProposals, a, b, c } = await this.generateEndTurnIntegrity({
|
|
997
|
+
gameId,
|
|
998
|
+
turn,
|
|
999
|
+
verifierAddress,
|
|
1000
|
+
size,
|
|
1001
|
+
proposals,
|
|
1002
|
+
});
|
|
1003
|
+
(0, log_1.logger)(`Generated proposals integrity with commitment ${commitment}`);
|
|
1004
|
+
return {
|
|
1005
|
+
newProposals: {
|
|
1006
|
+
a,
|
|
1007
|
+
b,
|
|
1008
|
+
c,
|
|
1009
|
+
proposals: permutedProposals,
|
|
1010
|
+
permutationCommitment: commitment,
|
|
1011
|
+
},
|
|
1012
|
+
permutation: permutation.map((p) => BigInt(p)),
|
|
1013
|
+
proposalsNotPermuted: proposals.map((proposal) => proposal.proposal),
|
|
1014
|
+
nullifier,
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Creates inputs for the proposal integrity circuit
|
|
1019
|
+
* @param params - Parameters including number of active proposals, proposals, commitment random numbers, game ID, turn, and verifier address
|
|
1020
|
+
* @returns The inputs for the proposal integrity circuit
|
|
1021
|
+
*/
|
|
1022
|
+
createInputs = async ({ numActive, proposals, commitmentRandomnesses, gameId, turn, verifierAddress, }) => {
|
|
1023
|
+
const poseidon = await (0, circomlibjs_1.buildPoseidon)();
|
|
1024
|
+
const maxSize = 15;
|
|
1025
|
+
// Initialize arrays with zeros
|
|
1026
|
+
const commitments = Array(maxSize).fill(0n);
|
|
1027
|
+
const randomnesses = Array(maxSize).fill(0n);
|
|
1028
|
+
const permutedProposals = Array(maxSize).fill(0n);
|
|
1029
|
+
// Generate deterministic permutation
|
|
1030
|
+
const { permutation, secret, commitment } = await this.generateDeterministicPermutation({
|
|
1031
|
+
gameId,
|
|
1032
|
+
turn,
|
|
1033
|
+
verifierAddress,
|
|
1034
|
+
size: numActive,
|
|
1035
|
+
});
|
|
1036
|
+
// Fill arrays with values
|
|
1037
|
+
for (let i = 0; i < maxSize; i++) {
|
|
1038
|
+
if (i < numActive) {
|
|
1039
|
+
// Active slots
|
|
1040
|
+
const proposal = proposals[i];
|
|
1041
|
+
const randomness = commitmentRandomnesses[i];
|
|
1042
|
+
const hash = poseidon([proposal, randomness]);
|
|
1043
|
+
commitments[i] = BigInt(poseidon.F.toObject(hash));
|
|
1044
|
+
randomnesses[i] = randomness;
|
|
1045
|
+
// Store proposal in permuted position
|
|
1046
|
+
permutedProposals[permutation[i]] = proposal;
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
// Inactive slots
|
|
1050
|
+
const hash = poseidon([0n, 0n]);
|
|
1051
|
+
commitments[i] = BigInt(poseidon.F.toObject(hash));
|
|
1052
|
+
randomnesses[i] = 0n;
|
|
1053
|
+
// permutedProposals already 0n
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
return {
|
|
1057
|
+
numActive: BigInt(numActive),
|
|
1058
|
+
commitments,
|
|
1059
|
+
permutedProposals,
|
|
1060
|
+
permutationCommitment: commitment,
|
|
1061
|
+
permutation: permutation.map((p) => BigInt(p)),
|
|
1062
|
+
randomnesses,
|
|
1063
|
+
permutationRandomness: secret,
|
|
1064
|
+
};
|
|
1065
|
+
};
|
|
394
1066
|
}
|
|
395
1067
|
exports.GameMaster = GameMaster;
|
|
396
1068
|
//# sourceMappingURL=GameMaster.js.map
|