refactor: standardises cosmos RPC methods alongside EIP155 ones

This commit is contained in:
Ben Kremer 2022-02-09 11:06:48 +01:00
parent 95751d6efb
commit d33bf9dcd1
2 changed files with 263 additions and 298 deletions

View File

@ -1,8 +1,6 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { version } from "@walletconnect/client/package.json"; import { version } from "@walletconnect/client/package.json";
// import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet";
import Banner from "./components/Banner"; import Banner from "./components/Banner";
import Blockchain from "./components/Blockchain"; import Blockchain from "./components/Blockchain";
import Column from "./components/Column"; import Column from "./components/Column";
@ -50,15 +48,7 @@ export default function App() {
setChains, setChains,
} = useWalletConnectClient(); } = useWalletConnectClient();
const { const { chainData, ping, ethereumRpc, cosmosRpc, isRpcRequestPending, rpcResult } = useJsonRpc();
chainData,
ping,
testSendTransaction,
testSignPersonalMessage,
testSignTypedData,
isRpcRequestPending,
rpcResult,
} = useJsonRpc();
useEffect(() => { useEffect(() => {
// Close the pairing modal after a session is established. // Close the pairing modal after a session is established.
@ -82,22 +72,20 @@ export default function App() {
await ping(); await ping();
}; };
const getEthereumActions = (): AccountAction[] => {
const onSendTransaction = async (chainId: string) => { const onSendTransaction = async (chainId: string) => {
openRequestModal(); openRequestModal();
await testSendTransaction(chainId); await ethereumRpc.testSendTransaction(chainId);
}; };
const onSignPersonalMessage = async (chainId: string) => { const onSignPersonalMessage = async (chainId: string) => {
openRequestModal(); openRequestModal();
await testSignPersonalMessage(chainId); await ethereumRpc.testSignPersonalMessage(chainId);
}; };
const onSignTypedData = async (chainId: string) => { const onSignTypedData = async (chainId: string) => {
openRequestModal(); openRequestModal();
await testSignTypedData(chainId); await ethereumRpc.testSignTypedData(chainId);
}; };
const getEthereumActions = (): AccountAction[] => {
return [ return [
{ method: "eth_sendTransaction", callback: onSendTransaction }, { method: "eth_sendTransaction", callback: onSendTransaction },
{ method: "personal_sign", callback: onSignPersonalMessage }, { method: "personal_sign", callback: onSignPersonalMessage },
@ -106,9 +94,17 @@ export default function App() {
}; };
const getCosmosActions = (): AccountAction[] => { const getCosmosActions = (): AccountAction[] => {
const onSignDirect = async (chainId: string) => {
openRequestModal();
await cosmosRpc.testSignDirect(chainId);
};
const onSignAmino = async (chainId: string) => {
openRequestModal();
await cosmosRpc.testSignAmino(chainId);
};
return [ return [
// { method: "cosmos_signDirect", callback: testSignDirect }, { method: "cosmos_signDirect", callback: onSignDirect },
// { method: "cosmos_signAmino", callback: testSignAmino }, { method: "cosmos_signAmino", callback: onSignAmino },
]; ];
}; };

View File

@ -1,6 +1,7 @@
import { BigNumber } from "ethers"; import { BigNumber } from "ethers";
import { createContext, ReactNode, useContext, useEffect, useState } from "react"; import { createContext, ReactNode, useContext, useEffect, useState } from "react";
import * as encoding from "@walletconnect/encoding"; import * as encoding from "@walletconnect/encoding";
import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet";
import { import {
ChainNamespaces, ChainNamespaces,
@ -31,9 +32,15 @@ interface IRpcResult {
interface IContext { interface IContext {
ping: () => Promise<void>; ping: () => Promise<void>;
ethereumRpc: {
testSendTransaction: (chainId: string) => Promise<void>; testSendTransaction: (chainId: string) => Promise<void>;
testSignPersonalMessage: (chainId: string) => Promise<void>; testSignPersonalMessage: (chainId: string) => Promise<void>;
testSignTypedData: (chainId: string) => Promise<void>; testSignTypedData: (chainId: string) => Promise<void>;
};
cosmosRpc: {
testSignDirect: (chainId: string) => Promise<void>;
testSignAmino: (chainId: string) => Promise<void>;
};
chainData: ChainNamespaces; chainData: ChainNamespaces;
rpcResult?: IRpcResult | null; rpcResult?: IRpcResult | null;
isRpcRequestPending: boolean; isRpcRequestPending: boolean;
@ -132,7 +139,10 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
} }
}; };
const testSendTransaction = _createJsonRpcRequestHandler(async (chainId: string) => { // -------- ETHEREUM/EIP155 RPC METHODS --------
const ethereumRpc = {
testSendTransaction: _createJsonRpcRequestHandler(async (chainId: string) => {
// get ethereum address // get ethereum address
const account = accounts.find(account => account.startsWith(chainId)); const account = accounts.find(account => account.startsWith(chainId));
if (account === undefined) throw new Error("Account is not found"); if (account === undefined) throw new Error("Account is not found");
@ -167,9 +177,8 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
valid: true, valid: true,
result, result,
}; };
}); }),
testSignPersonalMessage: _createJsonRpcRequestHandler(async (chainId: string) => {
const testSignPersonalMessage = _createJsonRpcRequestHandler(async (chainId: string) => {
// test message // test message
const message = `My email is john@doe.com - ${Date.now()}`; const message = `My email is john@doe.com - ${Date.now()}`;
@ -217,9 +226,8 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
valid, valid,
result, result,
}; };
}); }),
testSignTypedData: _createJsonRpcRequestHandler(async (chainId: string) => {
const testSignTypedData = _createJsonRpcRequestHandler(async (chainId: string) => {
// test message // test message
const message = JSON.stringify(eip712.example); const message = JSON.stringify(eip712.example);
@ -264,16 +272,138 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
valid, valid,
result, result,
}; };
}),
};
// -------- COSMOS RPC METHODS --------
const cosmosRpc = {
testSignDirect: _createJsonRpcRequestHandler(async (chainId: string) => {
// test direct sign doc inputs
const inputs = {
fee: [{ amount: "2000", denom: "ucosm" }],
pubkey: "AgSEjOuOr991QlHCORRmdE5ahVKeyBrmtgoYepCpQGOW",
gasLimit: 200000,
accountNumber: 1,
sequence: 1,
bodyBytes:
"0a90010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412700a2d636f736d6f7331706b707472653766646b6c366766727a6c65736a6a766878686c63337234676d6d6b38727336122d636f736d6f7331717970717870713971637273737a673270767871367273307a716733797963356c7a763778751a100a0575636f736d120731323334353637",
authInfoBytes:
"0a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a21034f04181eeba35391b858633a765c4a0c189697b40d216354d50890d350c7029012040a020801180112130a0d0a0575636f736d12043230303010c09a0c",
};
// split chainId
const [namespace, reference] = chainId.split(":");
// format sign doc
const signDoc = formatDirectSignDoc(
inputs.fee,
inputs.pubkey,
inputs.gasLimit,
inputs.accountNumber,
inputs.sequence,
inputs.bodyBytes,
reference,
);
// get cosmos address
const account = accounts.find(account => account.startsWith(chainId));
if (account === undefined) throw new Error("Account is not found");
const address = account.split(":").pop();
if (address === undefined) throw new Error("Address is invalid");
// cosmos_signDirect params
const params = {
signerAddress: address,
signDoc: stringifySignDocValues(signDoc),
};
// send message
const result = await client!.request({
topic: session!.topic,
chainId,
request: {
method: "cosmos_signDirect",
params,
},
}); });
const targetChainData = chainData[namespace][reference];
if (typeof targetChainData === "undefined") {
throw new Error(`Missing chain data for chainId: ${chainId}`);
}
// TODO: check if valid
const valid = true;
// format displayed result
return {
method: "cosmos_signDirect",
address,
valid,
result: result.signature.signature,
};
}),
testSignAmino: _createJsonRpcRequestHandler(async (chainId: string) => {
// split chainId
const [namespace, reference] = chainId.split(":");
// test amino sign doc
const signDoc = {
msgs: [],
fee: { amount: [], gas: "23" },
chain_id: "foochain",
memo: "hello, world",
account_number: "7",
sequence: "54",
};
// get cosmos address
const account = accounts.find(account => account.startsWith(chainId));
if (account === undefined) throw new Error("Account is not found");
const address = account.split(":").pop();
if (address === undefined) throw new Error("Address is invalid");
// cosmos_signAmino params
const params = { signerAddress: address, signDoc };
// send message
const result = await client!.request({
topic: session!.topic,
chainId,
request: {
method: "cosmos_signAmino",
params,
},
});
const targetChainData = chainData[namespace][reference];
if (typeof targetChainData === "undefined") {
throw new Error(`Missing chain data for chainId: ${chainId}`);
}
// TODO: check if valid
const valid = true;
// format displayed result
return {
method: "cosmos_signAmino",
address,
valid,
result: result.signature.signature,
};
}),
};
return ( return (
<JsonRpcContext.Provider <JsonRpcContext.Provider
value={{ value={{
chainData, chainData,
ping, ping,
testSendTransaction, ethereumRpc,
testSignPersonalMessage, cosmosRpc,
testSignTypedData,
rpcResult: result, rpcResult: result,
isRpcRequestPending: pending, isRpcRequestPending: pending,
}} }}
@ -290,164 +420,3 @@ export function useJsonRpc() {
} }
return context; return context;
} }
// ------ COSMOS RPC ------
// const testSignDirect = async (chainId: string) => {
// if (typeof client === "undefined") {
// throw new Error("WalletConnect is not initialized");
// }
// if (typeof session === "undefined") {
// throw new Error("Session is not connected");
// }
// try {
// // test direct sign doc inputs
// const inputs = {
// fee: [{ amount: "2000", denom: "ucosm" }],
// pubkey: "AgSEjOuOr991QlHCORRmdE5ahVKeyBrmtgoYepCpQGOW",
// gasLimit: 200000,
// accountNumber: 1,
// sequence: 1,
// bodyBytes:
// "0a90010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412700a2d636f736d6f7331706b707472653766646b6c366766727a6c65736a6a766878686c63337234676d6d6b38727336122d636f736d6f7331717970717870713971637273737a673270767871367273307a716733797963356c7a763778751a100a0575636f736d120731323334353637",
// authInfoBytes:
// "0a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a21034f04181eeba35391b858633a765c4a0c189697b40d216354d50890d350c7029012040a020801180112130a0d0a0575636f736d12043230303010c09a0c",
// };
// // split chainId
// const [namespace, reference] = chainId.split(":");
// // format sign doc
// const signDoc = formatDirectSignDoc(
// inputs.fee,
// inputs.pubkey,
// inputs.gasLimit,
// inputs.accountNumber,
// inputs.sequence,
// inputs.bodyBytes,
// reference,
// );
// // get cosmos address
// const account = accounts.find(account => account.startsWith(chainId));
// if (account === undefined) throw new Error("Account is not found");
// const address = account.split(":").pop();
// if (address === undefined) throw new Error("Address is invalid");
// // cosmos_signDirect params
// const params = {
// signerAddress: address,
// signDoc: stringifySignDocValues(signDoc),
// };
// // open modal
// openRequestModal();
// // send message
// const result = await client.request({
// topic: session.topic,
// chainId,
// request: {
// method: "cosmos_signDirect",
// params,
// },
// });
// const targetChainData = chainData[namespace][reference];
// if (typeof targetChainData === "undefined") {
// throw new Error(`Missing chain data for chainId: ${chainId}`);
// }
// // TODO: check if valid
// const valid = true;
// // format displayed result
// const formattedResult = {
// method: "cosmos_signDirect",
// address,
// valid,
// result: result.signature.signature,
// };
// // display result
// setResult(formattedResult);
// } catch (e) {
// console.error(e);
// setResult(null);
// } finally {
// setPending(false);
// }
// };
// const testSignAmino = async (chainId: string) => {
// if (typeof client === "undefined") {
// throw new Error("WalletConnect is not initialized");
// }
// if (typeof session === "undefined") {
// throw new Error("Session is not connected");
// }
// try {
// // split chainId
// const [namespace, reference] = chainId.split(":");
// // test amino sign doc
// const signDoc = {
// msgs: [],
// fee: { amount: [], gas: "23" },
// chain_id: "foochain",
// memo: "hello, world",
// account_number: "7",
// sequence: "54",
// };
// // get cosmos address
// const account = accounts.find(account => account.startsWith(chainId));
// if (account === undefined) throw new Error("Account is not found");
// const address = account.split(":").pop();
// if (address === undefined) throw new Error("Address is invalid");
// // cosmos_signAmino params
// const params = { signerAddress: address, signDoc };
// // open modal
// openRequestModal();
// // send message
// const result = await client.request({
// topic: session.topic,
// chainId,
// request: {
// method: "cosmos_signAmino",
// params,
// },
// });
// const targetChainData = chainData[namespace][reference];
// if (typeof targetChainData === "undefined") {
// throw new Error(`Missing chain data for chainId: ${chainId}`);
// }
// // TODO: check if valid
// const valid = true;
// // format displayed result
// const formattedResult = {
// method: "cosmos_signAmino",
// address,
// valid,
// result: result.signature.signature,
// };
// // display result
// setResult(formattedResult);
// } catch (e) {
// console.error(e);
// setResult(null);
// } finally {
// setPending(false);
// }
// };