Skip to content

Commit

Permalink
Merge pull request #835 from magiclabs/PDEEXP-2014-add-kadena-methods…
Browse files Browse the repository at this point in the history
…-to-sdk

feat: spire key methods
  • Loading branch information
hcote authored Dec 7, 2024
2 parents 53ebd1f + 7a5c8a4 commit 9ed96f6
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 58 deletions.
30 changes: 27 additions & 3 deletions packages/@magic-ext/kadena/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { Extension } from '@magic-sdk/commons';
import { KadenaConfig, KadenaPayloadMethod, KadenaSignTransactionResponse } from './types';
import {
UnsignedCommand,
KadenaConfig,
KadenaPayloadMethod,
KadenaUserMetadata,
SpireKeyAccount,
SignatureWithPublicKey,
SignedTransactions,
} from './types';

export class KadenaExtension extends Extension.Internal<'kadena'> {
name = 'kadena' as const;
Expand All @@ -13,14 +21,30 @@ export class KadenaExtension extends Extension.Internal<'kadena'> {
rpcUrl: kadenaConfig.rpcUrl,
chainId: kadenaConfig.chainId,
options: {
network: kadenaConfig.network,
networkId: kadenaConfig.networkId,
createAccountsOnChain: Boolean(kadenaConfig.createAccountsOnChain),
},
};
}

public signTransaction(hash: string): Promise<KadenaSignTransactionResponse> {
public signTransaction(hash: string): Promise<SignatureWithPublicKey> {
return this.request(this.utils.createJsonRpcRequestPayload(KadenaPayloadMethod.KadenaSignTransaction, [{ hash }]));
}

public async signTransactionWithSpireKey(transaction: UnsignedCommand): Promise<SignedTransactions> {
const signedTransaction = await this.request(
this.utils.createJsonRpcRequestPayload(KadenaPayloadMethod.KadenaSignTransactionWithSpireKey, [{ transaction }]),
);
return signedTransaction;
}

public loginWithSpireKey(): Promise<SpireKeyAccount> {
const requestPayload = this.utils.createJsonRpcRequestPayload(KadenaPayloadMethod.KadenaLoginWithSpireKey, []);
return this.request<SpireKeyAccount>(requestPayload);
}

public getUserInfo(): Promise<KadenaUserMetadata> {
const requestPayload = this.utils.createJsonRpcRequestPayload(KadenaPayloadMethod.KadenaGetUserInfo, []);
return this.request<KadenaUserMetadata>(requestPayload);
}
}
101 changes: 98 additions & 3 deletions packages/@magic-ext/kadena/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,115 @@
export interface KadenaConfig {
rpcUrl: string;
chainId: ChainId;
network: 'testnet' | 'mainnet';
networkId: string;
createAccountsOnChain?: boolean;
}

export enum KadenaPayloadMethod {
KadenaLoginWithSpireKey = 'kda_loginWithSpireKey',
KadenaGetUserInfo = 'kda_getUserInfo',
KadenaSignTransaction = 'kda_signTransaction',
KadenaSignTransactionWithSpireKey = 'kda_signTransactionWithSpireKey',
}

export interface KadenaSignTransactionResponse {
export interface SignatureWithPublicKey {
sig: string;
pubKey: string;
pubKey?: string;
}

export interface UnsignedCommand {
cmd: string;
hash: string;
sigs: Array<
| {
sig: string;
pubKey?: string;
}
| {
pubKey: string;
sig?: string;
}
| undefined
>;
}
export interface SignedCommand {
hash: string;
cmd: string;
sigs: {
sig: string;
pubKey?: string;
}[];
}

export interface SignedTransactions {
transactions: (UnsignedCommand | SignedCommand)[];
}

export interface KadenaUserMetadata {
accountName: string;
publicKey: string;
loginType: string;
isMfaEnabled: boolean;
email?: string;
phoneNumber?: string;
spireKeyInfo?: Account;
}

type Guard = RefKeyset | Keyset;

type RefKeyset = {
keysetref: {
ns: string;
ksn: string;
};
};

type Keyset = {
keys: string[];
pred: string;
};

type Device = {
domain: string;
color: string;
deviceType: string;
['credential-id']: string;
guard: Keyset;
pendingRegistrationTxs?: ITransactionDescriptor[];
name?: string;
};

interface ITransactionDescriptor {
requestKey: string;
chainId: ChainId;
networkId: string;
}

type QueuedTx = ITransactionDescriptor;

type RequestedFungible = {
fungible: string;
amount: number;
target?: ChainId;
};

type Account = {
alias: string;
accountName: string;
minApprovals: number;
minRegistrationApprovals: number;
balance: string;
devices: Device[];
guard?: Guard;
keyset?: Keyset;
networkId: string;
chainIds: ChainId[];
txQueue: QueuedTx[];
requestedFungibles?: RequestedFungible[];
};

export type SpireKeyAccount = Account;

export type ChainId =
| '0'
| '1'
Expand Down
63 changes: 62 additions & 1 deletion packages/@magic-ext/kadena/test/spec/kadena.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ beforeEach(() => {
browserEnv.restore();
});

test('Sends params as payload', () => {
test('signTransaction - Sends params as payload', () => {
const magic = createMagicSDKWithExtension({}, [
new KadenaExtension({
rpcUrl: '',
Expand All @@ -27,3 +27,64 @@ test('Sends params as payload', () => {
expect(requestPayload.method).toBe(KadenaPayloadMethod.KadenaSignTransaction);
expect(requestPayload.params).toEqual([{ hash: '0x123' }]);
});

test('signTransactionWithSpireKey - Sends params as payload', () => {
const magic = createMagicSDKWithExtension({}, [
new KadenaExtension({
rpcUrl: '',
chainId: '1',
networkId: 'testnet04',
network: 'testnet',
createAccountsOnChain: true,
}),
]);
magic.kadena.request = jest.fn();

const params = {
hash: '0x123',
cmd: '0x456',
sigs: [undefined],
};

magic.kadena.signTransactionWithSpireKey(params);

const requestPayload = magic.kadena.request.mock.calls[0][0];
expect(requestPayload.method).toBe(KadenaPayloadMethod.KadenaSignTransactionWithSpireKey);
expect(requestPayload.params).toEqual([{ transaction: params }]);
});

test('Generate JSON RPC request payload with method `kda_loginWithSpireKey`', () => {
const magic = createMagicSDKWithExtension({}, [
new KadenaExtension({
rpcUrl: '',
chainId: '1',
networkId: 'testnet04',
network: 'testnet',
createAccountsOnChain: true,
}),
]);
magic.kadena.request = jest.fn();

magic.kadena.loginWithSpireKey();

const requestPayload = magic.kadena.request.mock.calls[0][0];
expect(requestPayload.method).toBe(KadenaPayloadMethod.KadenaLoginWithSpireKey);
});

test('Generate JSON RPC request payload with method `kda_getUserInfo`', () => {
const magic = createMagicSDKWithExtension({}, [
new KadenaExtension({
rpcUrl: '',
chainId: '1',
networkId: 'testnet04',
network: 'testnet',
createAccountsOnChain: true,
}),
]);
magic.kadena.request = jest.fn();

magic.kadena.getUserInfo();

const requestPayload = magic.kadena.request.mock.calls[0][0];
expect(requestPayload.method).toBe(KadenaPayloadMethod.KadenaGetUserInfo);
});
Loading

0 comments on commit 9ed96f6

Please sign in to comment.