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