Part of https://www.notion.so/Stage0-onboarding-flow-1e4a6b22d47280aba3b5da3ed1154ff5 Co-authored-by: Shreerang Kale <shreerangkale@gmail.com> Reviewed-on: LaconicNetwork/laconic-wallet-web#27 Co-authored-by: shreerang <shreerang@noreply.git.vdb.to> Co-committed-by: shreerang <shreerang@noreply.git.vdb.to>
229 lines
6.7 KiB
TypeScript
229 lines
6.7 KiB
TypeScript
// Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a
|
|
import { BigNumber, Wallet, providers } from 'ethers';
|
|
|
|
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils';
|
|
import { SignClientTypes } from '@walletconnect/types';
|
|
import { getSdkError } from '@walletconnect/utils';
|
|
import {
|
|
SigningStargateClient,
|
|
StdFee,
|
|
MsgSendEncodeObject
|
|
} from '@cosmjs/stargate';
|
|
import { fromBech32 } from '@cosmjs/encoding';
|
|
import { EncodeObject } from '@cosmjs/proto-signing';
|
|
import { LaconicClient } from '@cerc-io/registry-sdk';
|
|
import { Buffer } from 'buffer';
|
|
|
|
import { EIP155_SIGNING_METHODS } from './EIP155Data';
|
|
import { signDirectMessage, signEthMessage } from '../sign-message';
|
|
import { Account } from '../../types';
|
|
import { getMnemonic, getPathKey } from '../misc';
|
|
import { getCosmosAccountByHDPath } from '../accounts';
|
|
import { COSMOS_METHODS } from './COSMOSData';
|
|
import { COSMOS } from '../constants';
|
|
|
|
interface EthSendTransaction {
|
|
type: 'eth_sendTransaction';
|
|
provider: providers.JsonRpcProvider;
|
|
ethGasLimit: BigNumber;
|
|
ethGasPrice: string | null;
|
|
maxPriorityFeePerGas: BigNumber | null;
|
|
maxFeePerGas: BigNumber | null;
|
|
}
|
|
|
|
interface SignMessage {
|
|
message: string;
|
|
}
|
|
interface EthPersonalSign extends SignMessage {
|
|
type: 'personal_sign';
|
|
}
|
|
|
|
interface CosmosSignDirect extends SignMessage {
|
|
type: 'cosmos_signDirect';
|
|
}
|
|
|
|
interface CosmosSignAmino extends SignMessage {
|
|
type: 'cosmos_signAmino';
|
|
}
|
|
|
|
interface CosmosSendTokens {
|
|
type: 'cosmos_sendTokens';
|
|
signingStargateClient: SigningStargateClient;
|
|
cosmosFee: StdFee;
|
|
sendMsg: MsgSendEncodeObject;
|
|
memo: string;
|
|
}
|
|
|
|
interface CosmosSendTransaction {
|
|
type: 'cosmos_sendTransaction';
|
|
LaconicClient: LaconicClient;
|
|
cosmosFee: StdFee;
|
|
txMsg: EncodeObject;
|
|
}
|
|
|
|
export type WalletConnectRequests =
|
|
| EthSendTransaction
|
|
| EthPersonalSign
|
|
| CosmosSignDirect
|
|
| CosmosSignAmino
|
|
| CosmosSendTokens
|
|
| CosmosSendTransaction;
|
|
|
|
export async function approveWalletConnectRequest(
|
|
requestEvent: SignClientTypes.EventArguments['session_request'],
|
|
account: Account,
|
|
namespace: string,
|
|
chainId: string,
|
|
options: WalletConnectRequests,
|
|
) {
|
|
const { params, id } = requestEvent;
|
|
const { request } = params;
|
|
|
|
const path = (await getPathKey(`${namespace}:${chainId}`, account.index))
|
|
.path;
|
|
const mnemonic = await getMnemonic();
|
|
|
|
let addressPrefix: string | undefined
|
|
if (namespace === COSMOS) {
|
|
addressPrefix = fromBech32(account.address).prefix
|
|
}
|
|
|
|
const cosmosAccount = await getCosmosAccountByHDPath(mnemonic, path, addressPrefix);
|
|
const address = account.address;
|
|
|
|
switch (request.method) {
|
|
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
|
|
if (!(options.type === 'eth_sendTransaction')) {
|
|
throw new Error('Incorrect parameters passed');
|
|
}
|
|
|
|
const privKey = (
|
|
await getPathKey(`${namespace}:${chainId}`, account.index)
|
|
).privKey;
|
|
const wallet = new Wallet(privKey);
|
|
const sendTransaction = request.params[0];
|
|
const updatedTransaction =
|
|
options.maxFeePerGas && options.maxPriorityFeePerGas
|
|
? {
|
|
...sendTransaction,
|
|
gasLimit: options.ethGasLimit,
|
|
maxFeePerGas: options.maxFeePerGas,
|
|
maxPriorityFeePerGas: options.maxPriorityFeePerGas,
|
|
type: 2,
|
|
}
|
|
: {
|
|
...sendTransaction,
|
|
gasLimit: options.ethGasLimit,
|
|
gasPrice: options.ethGasPrice,
|
|
type: 0,
|
|
};
|
|
|
|
const connectedWallet = wallet.connect(options.provider);
|
|
|
|
const hash = await connectedWallet.sendTransaction(updatedTransaction);
|
|
const receipt = typeof hash === 'string' ? hash : hash?.hash;
|
|
return formatJsonRpcResult(id, {
|
|
signature: receipt,
|
|
});
|
|
|
|
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
|
|
if (!(options.type === 'personal_sign')) {
|
|
throw new Error('Incorrect parameters passed');
|
|
}
|
|
|
|
const ethSignature = await signEthMessage(
|
|
options.message,
|
|
account.index,
|
|
chainId,
|
|
);
|
|
return formatJsonRpcResult(id, ethSignature);
|
|
|
|
case COSMOS_METHODS.COSMOS_SIGN_DIRECT:
|
|
// Reference: https://github.com/confio/cosmjs-types/blob/66e52711914fccd2a9d1a03e392d3628fdf499e2/src/cosmos/tx/v1beta1/tx.ts#L51
|
|
// According above doc, in the signDoc interface 'bodyBytes' and 'authInfoBytes' have Uint8Array type
|
|
if (!(options.type === 'cosmos_signDirect')) {
|
|
throw new Error('Incorrect parameters passed');
|
|
}
|
|
|
|
const bodyBytesArray = Uint8Array.from(
|
|
Buffer.from(request.params.signDoc.bodyBytes, 'hex'),
|
|
);
|
|
const authInfoBytesArray = Uint8Array.from(
|
|
Buffer.from(request.params.signDoc.authInfoBytes, 'hex'),
|
|
);
|
|
|
|
const cosmosDirectSignature = await signDirectMessage(
|
|
`${namespace}:${chainId}`,
|
|
account.index,
|
|
{
|
|
...request.params.signDoc,
|
|
bodyBytes: bodyBytesArray,
|
|
authInfoBytes: authInfoBytesArray,
|
|
},
|
|
);
|
|
|
|
return formatJsonRpcResult(id, {
|
|
signature: cosmosDirectSignature,
|
|
});
|
|
|
|
case COSMOS_METHODS.COSMOS_SIGN_AMINO:
|
|
if (!(options.type === 'cosmos_signAmino')) {
|
|
throw new Error('Incorrect parameters passed');
|
|
}
|
|
|
|
const cosmosAminoSignature = await cosmosAccount.cosmosWallet.signAmino(
|
|
address,
|
|
request.params.signDoc,
|
|
);
|
|
|
|
if (!cosmosAminoSignature) {
|
|
throw new Error('Error signing message');
|
|
}
|
|
|
|
return formatJsonRpcResult(id, {
|
|
signature: cosmosAminoSignature.signature.signature,
|
|
});
|
|
|
|
case COSMOS_METHODS.COSMOS_SEND_TOKENS:
|
|
if (!(options.type === 'cosmos_sendTokens')) {
|
|
throw new Error('Incorrect parameters passed');
|
|
}
|
|
|
|
const result = await options.signingStargateClient.signAndBroadcast(
|
|
address,
|
|
[options.sendMsg],
|
|
options.cosmosFee,
|
|
options.memo,
|
|
);
|
|
|
|
return formatJsonRpcResult(id, {
|
|
signature: result.transactionHash,
|
|
});
|
|
|
|
case COSMOS_METHODS.COSMOS_SEND_TRANSACTION:
|
|
if (!(options.type === 'cosmos_sendTransaction')) {
|
|
throw new Error('Incorrect parameters passed');
|
|
}
|
|
const resultFromTx = await options.LaconicClient.signAndBroadcast(
|
|
address,
|
|
[options.txMsg],
|
|
options.cosmosFee,
|
|
);
|
|
|
|
return formatJsonRpcResult(id, {
|
|
code: resultFromTx.code,
|
|
});
|
|
|
|
default:
|
|
throw new Error(getSdkError('INVALID_METHOD').message);
|
|
}
|
|
}
|
|
|
|
export function rejectWalletConnectRequest(
|
|
request: SignClientTypes.EventArguments['session_request'],
|
|
) {
|
|
const { id } = request;
|
|
|
|
return formatJsonRpcError(id, getSdkError('USER_REJECTED_METHODS').message);
|
|
}
|