Skip to content

Commit

Permalink
feat: add eip6963 support
Browse files Browse the repository at this point in the history
  • Loading branch information
ashuralyk committed Aug 13, 2024
1 parent 4f9ca56 commit cad6a46
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 44 deletions.
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"dependencies": {
"@ckb-ccc/core": "0.0.11-alpha.3",
"@ckb-ccc/eip6963": "0.0.11-alpha.3",
"@ckb-ccc/joy-id": "0.0.11-alpha.3",
"@ckb-ccc/utxo-global": "0.0.11-alpha.3"
}
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ export * from './joints/mutant/getMutant';
* Signers
*/

export * from './signers/abstract';
export * from './signers/joyId';
export * from './signers/privkey';
export * from './signers/utxoGlobal';
// TODO: Metamask Support
export * from './signers/eip6963';
30 changes: 30 additions & 0 deletions packages/core/src/api/signers/abstract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { helpers } from '@ckb-lumos/lumos';
import { ccc } from '@ckb-ccc/core';

/**
* Sign a Lumos transaction with the specified signer.
*
* @param skeleton The Lumos transaction skeleton.
* @param signer An abstract signer from ccc to sign the transaction.
* @param send Whether to send the transaction after signing. Default is false.
* @returns The signed transaction and the transaction hash if `send` is set to True.
*/
export async function signTransaction(props: {
skeleton: helpers.TransactionSkeletonType;
signer: ccc.Signer;
send?: boolean;
}): Promise<{
cccTx: ccc.Transaction;
txHash?: ccc.Hex;
}> {
const send = props.send ?? false;
const signer = props.signer;
const tx = ccc.Transaction.fromLumosSkeleton(props.skeleton);
const signedTx = await signer.signTransaction(tx);
if (send) {
const txHash = await signer.sendTransaction(signedTx);
return { cccTx: signedTx, txHash };
} else {
return { cccTx: signedTx };
}
}
63 changes: 63 additions & 0 deletions packages/core/src/api/signers/eip6963.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { ccc } from '@ckb-ccc/core';
import { Eip6963 } from '@ckb-ccc/eip6963';
import { ProviderDetail } from '@ckb-ccc/eip6963/src/eip6963.advanced';
import { helpers } from '@ckb-lumos/lumos';
import { signTransaction } from './abstract';

let mainnetEip6963Signer: Eip6963.Signer | undefined = undefined;
let testnetEip6963Signer: Eip6963.Signer | undefined = undefined;

/**
* Get the raw Eip6963 signer according to the network type.
*
* @param network The network type, either "mainnet" or "testnet".
* @returns The Eip6963 signer.
*/
export function getEip6963Signer(network: 'mainnet' | 'testnet'): Eip6963.Signer {
const windowRef = window as { ethereum?: ProviderDetail };

if (!windowRef.ethereum) {
throw new Error('Eip6963 compatible wallet is not loaded');
}

if (network === 'mainnet') {
if (mainnetEip6963Signer) {
return mainnetEip6963Signer;
}
const client = new ccc.ClientPublicMainnet();
mainnetEip6963Signer = new Eip6963.Signer(client, windowRef.ethereum);
return mainnetEip6963Signer;
} else {
if (testnetEip6963Signer) {
return testnetEip6963Signer;
}
const client = new ccc.ClientPublicTestnet();
testnetEip6963Signer = new Eip6963.Signer(client, windowRef.ethereum);
return testnetEip6963Signer;
}
}

/**
* Sign a Lumos transaction with Eip6963 compatible wallet.
*
* @param skeleton The Lumos transaction skeleton.
* @param network The network type, either "mainnet" or "testnet".
* @param send Whether to send the transaction after signing. Default is false.
* @returns The signed transaction and the transaction hash if `send` is set to True.
*/
export async function signTransactionWithEip6963CompatibleWallet(props: {
skeleton: helpers.TransactionSkeletonType;
network: 'mainnet' | 'testnet';
privkey: ccc.Hex;
send?: boolean;
}): Promise<{
cccTx: ccc.Transaction;
txHash?: ccc.Hex;
}> {
const send = props.send ?? false;
const signer = getEip6963Signer(props.network);
if (!signer.isConnected()) {
await signer.connect();
}
return await signTransaction({ skeleton: props.skeleton, signer, send });
}
22 changes: 6 additions & 16 deletions packages/core/src/api/signers/joyId.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { ccc } from '@ckb-ccc/core';
import { JoyId } from '@ckb-ccc/joy-id';
import { helpers } from '@ckb-lumos/lumos';
import { signTransaction } from './abstract';

let mainnetJoyIdSigner: JoyId.CkbSigner | undefined = undefined;
let testnetJoyIdSigner: JoyId.CkbSigner | undefined = undefined;

export interface SignerInfo {
network: 'mainnet' | 'testnet';
name: string;
url: string;
appName: string;
logoUrl: string;
}

/**
Expand All @@ -23,14 +24,14 @@ export function getJoyIdSigner(signerInfo: SignerInfo): JoyId.CkbSigner {
return mainnetJoyIdSigner;
}
const client = new ccc.ClientPublicMainnet();
mainnetJoyIdSigner = new JoyId.CkbSigner(client, signerInfo.name, signerInfo.url);
mainnetJoyIdSigner = new JoyId.CkbSigner(client, signerInfo.appName, signerInfo.logoUrl);
return mainnetJoyIdSigner;
} else {
if (testnetJoyIdSigner) {
return testnetJoyIdSigner;
}
const client = new ccc.ClientPublicTestnet();
testnetJoyIdSigner = new JoyId.CkbSigner(client, signerInfo.name, signerInfo.url);
testnetJoyIdSigner = new JoyId.CkbSigner(client, signerInfo.appName, signerInfo.logoUrl);
return testnetJoyIdSigner;
}
}
Expand All @@ -56,16 +57,5 @@ export async function signTransactionWithJoyId(props: {
if (!signer.isConnected()) {
await signer.connect();
}
const tx = ccc.Transaction.fromLumosSkeleton(props.skeleton);
const signedTx = await signer.signTransaction(tx);

let txHash: ccc.Hex | undefined = undefined;
if (send) {
txHash = await signer.client.sendTransaction(signedTx);
}

return {
cccTx: signedTx,
txHash,
};
return await signTransaction({ skeleton: props.skeleton, signer, send });
}
22 changes: 8 additions & 14 deletions packages/core/src/api/signers/privkey.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { helpers } from '@ckb-lumos/lumos';
import { ccc } from '@ckb-ccc/core';
import { signTransaction } from './abstract';

/**
* Sign a Lumos transaction with a private key in direct, mostly used in backend server.
*
* @param skeleton The Lumos transaction skeleton.
* @param network The network type, either "mainnet" or "testnet".
* @param privkey The private key in hex format.
* @param network The network type, either "mainnet" or "testnet". Default is "testnet".
* @param send Whether to send the transaction after signing. Default is false.
* @returns The signed transaction and the transaction hash if `send` is True.
*/
export async function signTransactionWithPrivateKey(props: {
skeleton: helpers.TransactionSkeletonType;
network: 'mainnet' | 'testnet';
privkey: ccc.Hex;
network?: 'mainnet' | 'testnet';
send?: boolean;
}): Promise<{
cccTx: ccc.Transaction;
txHash?: ccc.Hex;
}> {
let network = props.network;
if (!network) {
network = 'testnet';
}
let client: ccc.Client | undefined = undefined;
if (props.network === 'mainnet') {
client = new ccc.ClientPublicMainnet();
Expand All @@ -27,17 +32,6 @@ export async function signTransactionWithPrivateKey(props: {
}

const send = props.send ?? false;
const tx = ccc.Transaction.fromLumosSkeleton(props.skeleton);
const privkeySigner = new ccc.SignerCkbPrivateKey(client, props.privkey);
const signedTx = await privkeySigner.signTransaction(tx);

let txHash: ccc.Hex | undefined = undefined;
if (send) {
txHash = await client.sendTransaction(signedTx);
}

return {
cccTx: signedTx,
txHash,
};
return await signTransaction({ skeleton: props.skeleton, signer: privkeySigner, send });
}
16 changes: 3 additions & 13 deletions packages/core/src/api/signers/utxoGlobal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { helpers } from '@ckb-lumos/lumos';
import { ccc } from '@ckb-ccc/core';
import { UtxoGlobal } from '@ckb-ccc/utxo-global';
import { Provider } from '@ckb-ccc/utxo-global/src/advancedBarrel';
import { signTransaction } from './abstract';

let mainnetUtxoGlobalSigner: UtxoGlobal.SignerCkb | undefined = undefined;
let testnetUtxoGlobalSigner: UtxoGlobal.SignerCkb | undefined = undefined;
Expand Down Expand Up @@ -55,23 +56,12 @@ export async function signTransactionWithUtxoGlobal(props: {
send?: boolean;
}): Promise<{
cccTx: ccc.Transaction;
txHash: ccc.Hex;
txHash?: ccc.Hex;
}> {
const send = props.send ?? false;
const signer = getUtxoGlobalSigner(props.network);
if (!signer.isConnected()) {
await signer.connect();
}
const tx = ccc.Transaction.fromLumosSkeleton(props.skeleton);
const signedTx = await signer.signTransaction(tx);

let txHash: ccc.Hex | undefined = undefined;
if (send) {
txHash = await signer.client.sendTransaction(signedTx);
}

return {
cccTx: signedTx,
txHash: txHash!,
};
return await signTransaction({ skeleton: props.skeleton, signer, send });
}
15 changes: 15 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cad6a46

Please sign in to comment.