Created
September 22, 2025 16:36
-
-
Save denniswon/94b77627250b44347703055ec4ebfff0 to your computer and use it in GitHub Desktop.
newton client side: rpc request for simulatePolicyEvaluation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { | |
| createWalletClient, | |
| createPublicClient, | |
| http, | |
| parseEther, | |
| keccak256, | |
| encodePacked, | |
| Address, | |
| Hex, | |
| PrivateKeyAccount, | |
| privateKeyToAccount, | |
| } from "viem"; | |
| import { mainnet, sepolia, holesky } from "viem/chains"; | |
| // Types for Newton RPC API | |
| interface Intent { | |
| from: Address; | |
| to: Address; | |
| value: bigint; | |
| data: Hex; | |
| chainId: bigint; | |
| functionSignature: Hex; | |
| } | |
| interface PolicyData { | |
| data: Hex; | |
| attestation: Hex; | |
| policyDataAddress: Address; | |
| expireBlock: number; | |
| } | |
| interface PolicyTaskData { | |
| policyId: Hex; | |
| policyAddress: Address; | |
| policy: Hex; | |
| policyData: PolicyData[]; | |
| } | |
| interface SimulatePolicyEvaluationRequest { | |
| signature: string; | |
| intent: Intent; | |
| policy_task_data: PolicyTaskData; | |
| } | |
| interface SimulatePolicyEvaluationResponse { | |
| /// something like this | |
| result: { | |
| policy: string, | |
| parsed_intent: ParsedIntent, | |
| policy_params_and_data: JsonObject, | |
| entrypoint: string, | |
| result: JsonObject, | |
| expire_after: number, | |
| } | |
| } | |
| // Newton RPC Client Class | |
| export class NewtonRpcClient { | |
| private rpcUrl: string; | |
| private walletClient: any; | |
| private publicClient: any; | |
| constructor( | |
| rpcUrl: string, | |
| privateKey: Hex, | |
| chainId: number = 11155111 | |
| ) { | |
| this.rpcUrl = rpcUrl; | |
| // Create account from private key | |
| const account = privateKeyToAccount(privateKey); | |
| // Select chain based on chainId | |
| const chain = this.getChainById(chainId); | |
| // Create clients | |
| this.walletClient = createWalletClient({ | |
| account, | |
| chain, | |
| transport: http(), | |
| }); | |
| this.publicClient = createPublicClient({ | |
| chain, | |
| transport: http(), | |
| }); | |
| } | |
| private getChainById(chainId: number) { | |
| switch (chainId) { | |
| case 1: | |
| return mainnet; | |
| case 11155111: | |
| return sepolia; | |
| case 17000: | |
| return holesky; | |
| default: | |
| return mainnet; | |
| } | |
| } | |
| /** | |
| * Creates the hash for signing the request | |
| * This matches the Rust implementation: keccak256(abi_encode_packed(request)) | |
| */ | |
| private createRequestHash( | |
| intent: Intent, | |
| policyTaskData: PolicyTaskData | |
| ): Hex { | |
| // ABI encode packed the request data | |
| // This matches the ISimulatePolicyEvaluationRequest struct | |
| const encoded = encodePacked( | |
| ["address", "address", "uint256", "bytes", "uint256", "bytes"], // Intent fields | |
| [ | |
| intent.from, | |
| intent.to, | |
| intent.value, | |
| intent.data, | |
| intent.chainId, | |
| intent.functionSignature, | |
| ] | |
| ); | |
| // Add PolicyTaskData fields | |
| const policyTaskDataEncoded = encodePacked( | |
| ["bytes32", "address", "bytes", "uint256"], // policyId, policyAddress, policy, policyData length | |
| [ | |
| policyTaskData.policyId, | |
| policyTaskData.policyAddress, | |
| policyTaskData.policy, | |
| BigInt(policyTaskData.policyData.length), | |
| ] | |
| ); | |
| // Encode each PolicyData item | |
| let policyDataEncoded = "0x"; | |
| for (const pd of policyTaskData.policyData) { | |
| const pdEncoded = encodePacked( | |
| ["bytes", "bytes", "address", "uint32"], | |
| [pd.data, pd.attestation, pd.policyDataAddress, pd.expireBlock] | |
| ); | |
| policyDataEncoded += pdEncoded.slice(2); // Remove 0x prefix | |
| } | |
| // Combine all encoded data | |
| const fullEncoded = | |
| encoded + policyTaskDataEncoded.slice(2) + policyDataEncoded.slice(2); | |
| // Create keccak256 hash | |
| return keccak256(fullEncoded as Hex); | |
| } | |
| /** | |
| * Signs the request hash with the wallet's private key | |
| */ | |
| private async signRequest(hash: Hex): Promise<string> { | |
| const signature = await this.walletClient.signMessage({ | |
| message: { raw: hash }, | |
| }); | |
| return signature; | |
| } | |
| /** | |
| * Simulates policy evaluation by calling the Newton RPC endpoint | |
| */ | |
| async simulatePolicyEvaluation( | |
| intent: Intent, | |
| policyTaskData: PolicyTaskData | |
| ): Promise<SimulatePolicyEvaluationResponse> { | |
| // Create the hash for signing | |
| const requestHash = this.createRequestHash(intent, policyTaskData); | |
| // Sign the request | |
| const signature = await this.signRequest(requestHash); | |
| // Create the request object | |
| const request: SimulatePolicyEvaluationRequest = { | |
| signature, | |
| intent, | |
| policy_task_data: policyTaskData, | |
| }; | |
| // Make the RPC call | |
| const response = await fetch(this.rpcUrl, { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify({ | |
| jsonrpc: "2.0", | |
| method: "newton_simulatePolicyEvaluation", | |
| params: [request], | |
| id: 1, | |
| }), | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| const result = await response.json(); | |
| if (result.error) { | |
| throw new Error(`RPC error: ${result.error.message}`); | |
| } | |
| return result.result; | |
| } | |
| /** | |
| * Get the current account address | |
| */ | |
| getAddress(): Address { | |
| return this.walletClient.account.address; | |
| } | |
| } | |
| // Example usage | |
| export async function exampleUsage() { | |
| // Initialize the client | |
| const rpcUrl = "https://prover-avs.stagef.newt.foundation"; | |
| const privateKey = "0x..." as Hex; // Your private key of an account that is whitelisted | |
| const client = new NewtonRpcClient(rpcUrl, privateKey, 1); // mainnet | |
| console.log("Using address:", client.getAddress()); | |
| // Example intent - replace with your actual values | |
| const intent: Intent = { | |
| from: "0x1234567890123456789012345678901234567890" as Address, | |
| to: "0x0987654321098765432109876543210987654321" as Address, | |
| value: parseEther("1.0"), // 1 ETH | |
| data: "0x" as Hex, // Transaction data | |
| chainId: BigInt(1), // Mainnet | |
| functionSignature: "0x" as Hex, // Function signature | |
| }; | |
| // Example policy task data - replace with your actual values | |
| const policyTaskData: PolicyTaskData = { | |
| policyId: | |
| "0x1234567890123456789012345678901234567890123456789012345678901234" as Hex, | |
| policyAddress: "0x1234567890123456789012345678901234567890" as Address, | |
| policy: "0x" as Hex, // Policy bytes | |
| policyData: [ | |
| { | |
| data: "0x" as Hex, | |
| attestation: "0x" as Hex, | |
| policyDataAddress: | |
| "0x1234567890123456789012345678901234567890" as Address, | |
| expireBlock: 19000000, | |
| }, | |
| ], | |
| }; | |
| try { | |
| // Call the simulate policy evaluation endpoint | |
| const result = await client.simulatePolicyEvaluation( | |
| intent, | |
| policyTaskData | |
| ); | |
| console.log("Policy evaluation result:", result); | |
| } catch (error) { | |
| console.error("Error calling simulate policy evaluation:", error); | |
| } | |
| } | |
| // Export for use in other modules | |
| export { | |
| NewtonRpcClient, | |
| type Intent, | |
| type PolicyData, | |
| type PolicyTaskData, | |
| type SimulatePolicyEvaluationRequest, | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment