Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using different active and owner keys #13

Merged
merged 9 commits into from
Dec 5, 2024
7 changes: 6 additions & 1 deletion packages/site/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import { TransactPluginResourceProvider } from '@wharfkit/transact-plugin-resource-provider';
import { WalletPluginMetaMask } from '@wharfkit/wallet-plugin-metamask';
import { AccountCreationPluginMetamask } from '@wharfkit/account-creation-plugin-metamask';
import { defaultSnapOrigin } from '../config/snap';

let provider: MetaMaskInpageProvider;
const session: Writable<Session | undefined> = writable();
Expand All @@ -26,7 +27,11 @@
},
{
transactPlugins: [new TransactPluginResourceProvider()],
accountCreationPlugins: [new AccountCreationPluginMetamask()]
accountCreationPlugins: [
new AccountCreationPluginMetamask({
snapOrigin: defaultSnapOrigin
})
]
}
);

Expand Down
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/@greymass/antelope-snap.git"
},
"source": {
"shasum": "m24q8fHmbJ5EWc1RDiD77ZphcUuxAPJ2M7Fo2TEfkG8=",
"shasum": "qbEi3wUvdBWmFB6QXs3uzvEI6TDJGXCVgfMRiDo3cFs=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
19 changes: 15 additions & 4 deletions packages/snap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import {
panel,
} from '@metamask/snaps-sdk';

import { getPublicKey, signTransaction } from './rpc';
import { AntelopeRequest, AntelopeSignatureRequest } from './types';
import { signTransaction, getOwnerPublicKey, getActivePublicKey } from './rpc';
import type {
AntelopeSignatureRequest,
AntelopeGetOwnerPublicKeyRequest,
AntelopeGetActivePublicKeyRequest,
} from './types';

const SNAP_NAME = 'EOS Wallet';
const HELP_URL = 'https://unicove.com/eos/metamask';
Expand Down Expand Up @@ -44,8 +48,15 @@ export const onInstall: OnInstallHandler = async () => {
*/
export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
switch (request.method) {
case 'antelope_getPublicKey':
return await getPublicKey(request as AntelopeRequest);
case 'antelope_getOwnerPublicKey':
return await getOwnerPublicKey(
request as AntelopeGetOwnerPublicKeyRequest,
);

case 'antelope_getActivePublicKey':
return await getActivePublicKey(
request as AntelopeGetActivePublicKeyRequest,
);

case 'antelope_signTransaction':
return String(await signTransaction(request as AntelopeSignatureRequest));
Expand Down
79 changes: 62 additions & 17 deletions packages/snap/src/lib/keyDeriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,81 @@ async function getKeyDeriver(chain: ChainDefinition) {
}

/**
* Derive an Antelope public key from the key tree at the given address index.
* Derive an Antelope private key from the key tree at the given address index.
*
* @param addressIndex - The index of the address to derive.
* @returns The public key.
* @param keyIndex - The index of the key to derive.
* @returns The private key.
* @throws If the key tree is not initialized.
*/
export async function derivePublicKey(
async function derivePrivateKey(
chain: ChainDefinition,
keyIndex = 1, // default to first active key
): Promise<PrivateKey> {
const keyDeriver = await getKeyDeriver(chain);
const derived = await keyDeriver(keyIndex);

if (!derived.privateKeyBytes) {
throw new Error('Private key not found');
}

return new PrivateKey(KeyType.K1, Bytes.from(derived.privateKeyBytes));
}

/**
* Derive an Antelope owner public key from the key tree.
* Always uses index 0 which is reserved for owner permissions.
*
* @returns The owner public key.
* @throws If the key tree is not initialized.
*/
export async function deriveOwnerPublicKey(
chain: ChainDefinition,
addressIndex = 0,
): Promise<PublicKey> {
return (await derivePrivateKey(chain, addressIndex)).toPublic();
return (await deriveOwnerPrivateKey(chain)).toPublic();
}

/**
* Derive an Antelope private key from the key tree at the given address index.
* Derive an Antelope active public key from the key tree.
* Cannot use index 0 which is reserved for owner permissions.
*
* @param addressIndex - The index of the address to derive.
* @returns The private key.
* @param keyIndex - The index of the address to derive (must not be 0).
* @returns The active public key.
* @throws If the key tree is not initialized or if index 0 is used.
*/
export async function deriveActivePublicKey(
chain: ChainDefinition,
keyIndex = 1,
): Promise<PublicKey> {
return (await deriveActivePrivateKey(chain, keyIndex)).toPublic();
}

/**
* Derive an Antelope owner private key from the key tree.
* Always uses index 0 which is reserved for owner permissions.
*
* @returns The owner private key.
* @throws If the key tree is not initialized.
*/
export async function derivePrivateKey(
export async function deriveOwnerPrivateKey(
chain: ChainDefinition,
addressIndex = 0,
): Promise<PrivateKey> {
const keyDeriver = await getKeyDeriver(chain);
const derived = await keyDeriver(addressIndex);
return derivePrivateKey(chain, 0);
}

if (!derived.privateKeyBytes) {
throw new Error('Private key not found');
/**
* Derive an Antelope active private key from the key tree.
* Cannot use index 0 which is reserved for owner permissions.
*
* @param keyIndex - The index of the address to derive (must not be 0).
* @returns The active private key.
* @throws If the key tree is not initialized or if index 0 is used.
*/
export async function deriveActivePrivateKey(
chain: ChainDefinition,
keyIndex = 1,
): Promise<PrivateKey> {
if (Number(keyIndex) > 0) {
return derivePrivateKey(chain, Number(keyIndex));
}

return new PrivateKey(KeyType.K1, Bytes.from(derived.privateKeyBytes));
throw new Error('Invalid key index');
}
34 changes: 29 additions & 5 deletions packages/snap/src/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@ import {
} from '@wharfkit/antelope';
import { ChainDefinition, Chains, chainIdsToIndices } from '@wharfkit/common';

import { derivePrivateKey, derivePublicKey } from './lib/keyDeriver';
import { AntelopeRequest, AntelopeSignatureRequest } from './types';
import {
deriveActivePublicKey,
deriveOwnerPublicKey,
deriveActivePrivateKey,
} from './lib/keyDeriver';
import {
AntelopeGetActivePublicKeyRequest,
AntelopeGetOwnerPublicKeyRequest,
AntelopeSignatureRequest,
} from './types';

export function chainIdToDefinition(chainId: Checksum256Type): ChainDefinition {
const index = chainIdsToIndices.get(String(chainId));
Expand All @@ -20,13 +28,26 @@ export function chainIdToDefinition(chainId: Checksum256Type): ChainDefinition {
return Chains[index];
}

export async function getPublicKey(request: AntelopeRequest): Promise<string> {
export async function getOwnerPublicKey(
request: AntelopeGetOwnerPublicKeyRequest,
): Promise<string> {
if (!request.params?.chainId) {
throw new Error('Missing chainId in request params');
}
const chain = chainIdToDefinition(request.params.chainId);

return String(await deriveOwnerPublicKey(chain));
}

export async function getActivePublicKey(
request: AntelopeGetActivePublicKeyRequest,
): Promise<string> {
if (!request.params?.chainId) {
throw new Error('Missing chainId in request params');
}
const chain = chainIdToDefinition(request.params.chainId);

return String(await derivePublicKey(chain));
return String(await deriveActivePublicKey(chain, request.params.keyIndex));
}

const MAX_TRANSACTION_LENGTH = 100_000;
Expand Down Expand Up @@ -115,7 +136,10 @@ export async function signTransaction(

// If confirmed, sign the transaction
if (confirmed) {
const privateKey = await derivePrivateKey(chain);
const privateKey = await deriveActivePrivateKey(
chain,
request.params?.keyIndex,
);
return privateKey.signDigest(transaction.signingDigest(chain.id));
}

Expand Down
16 changes: 12 additions & 4 deletions packages/snap/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { JsonRpcRequest } from '@metamask/snaps-sdk';

export interface AntelopeRequest extends JsonRpcRequest {
export interface AntelopeSignatureRequest extends JsonRpcRequest {
params?: {
chainId: string;
transaction: string;
keyIndex?: number;
};
}

export interface AntelopeSignatureRequest extends JsonRpcRequest {
params?: {
export interface AntelopeGetOwnerPublicKeyRequest extends JsonRpcRequest {
params: {
chainId: string;
transaction: string;
};
}

export interface AntelopeGetActivePublicKeyRequest extends JsonRpcRequest {
params: {
chainId: string;
keyIndex?: number;
};
}
Loading