Skip to content

Commit

Permalink
TRCL-3691 v4-client: Add signing function for push (#233)
Browse files Browse the repository at this point in the history
* Add native function to sign push notification token registration payload

* Bump version

* Fix

* Clean up

* Clean up
  • Loading branch information
ruixhuang authored and yogurtandjam committed Sep 16, 2024
1 parent 0445b72 commit 5ff27c0
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
77 changes: 65 additions & 12 deletions v4-client-js/__native__/__ios__/v4-native-client.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions v4-client-js/package-lock.json

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

2 changes: 1 addition & 1 deletion v4-client-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dydxprotocol/v4-client-js",
"version": "1.3.1",
"version": "1.3.2",
"description": "General client library for the new dYdX system (v4 decentralized)",
"main": "build/src/index.js",
"scripts": {
Expand Down
36 changes: 35 additions & 1 deletion v4-client-js/src/clients/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Long from 'long';
import { BECH32_PREFIX, GAS_MULTIPLIER, NOBLE_BECH32_PREFIX } from '../lib/constants';
import { UserError } from '../lib/errors';
import { ByteArrayEncoding, encodeJson } from '../lib/helpers';
import { deriveHDKeyFromEthereumSignature } from '../lib/onboarding';
import { deriveHDKeyFromEthereumSignature, deriveHDKeyFromMnemonic } from '../lib/onboarding';
import { NetworkOptimizer } from '../network_optimizer';
import { CompositeClient, MarketInfo } from './composite-client';
import {
Expand Down Expand Up @@ -147,6 +147,12 @@ export async function connectWallet(mnemonic: string): Promise<string> {
globalThis.wallet = await LocalWallet.fromMnemonic(mnemonic, BECH32_PREFIX);
globalThis.nobleWallet = await LocalWallet.fromMnemonic(mnemonic, NOBLE_BECH32_PREFIX);

const { privateKey, publicKey } = deriveHDKeyFromMnemonic(mnemonic);
globalThis.hdKey = {
privateKey,
publicKey,
};

try {
await globalThis.nobleClient?.connect(globalThis.nobleWallet);
} catch (e) {
Expand Down Expand Up @@ -1306,6 +1312,34 @@ export async function signCompliancePayload(payload: string): Promise<string> {
}
}

export async function signPushNotificationTokenRegistrationPayload(payload: string): Promise<string> {
try {
const json = JSON.parse(payload);
const message = json.message;
if (message === undefined) {
throw new UserError('message is not set');
}
if (!globalThis.hdKey?.privateKey || !globalThis.hdKey?.publicKey) {
throw new Error('Missing hdKey');
}

const timestampInSeconds = Math.floor(Date.now() / 1000);
const messageToSign: string = `${message}:REGISTER_TOKEN"${''}:${timestampInSeconds}`;
const messageHash = sha256(Buffer.from(messageToSign));

const signed = await Secp256k1.createSignature(messageHash, globalThis.hdKey.privateKey);
const signedMessage = signed.toFixedLength();

return encodeJson({
signedMessage: Buffer.from(signedMessage).toString('base64'),
publicKey: Buffer.from(globalThis.hdKey.publicKey).toString('base64'),
timestamp: timestampInSeconds,
});
} catch (error) {
return wrappedError(error);
}
}

export async function setSelectedGasDenom(gasDenom: string): Promise<string> {
try {
const client = globalThis.client;
Expand Down
49 changes: 38 additions & 11 deletions v4-client-js/src/lib/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,11 @@ export const exportMnemonicAndPrivateKey = (
publicKey: Uint8Array | null;
} => {
const mnemonic = entropyToMnemonic(entropy, wordlist);
const seed = mnemonicToSeedSync(mnemonic);

const hdkey = HDKey.fromMasterSeed(seed);
const derivedHdkey = hdkey.derive(path);

if (!hdkey.privateKey) {
throw new Error('null hd key');
}

const { privateKey, publicKey } = deriveHDKeyFromMnemonic(mnemonic, path);
return {
mnemonic,
privateKey: derivedHdkey.privateKey,
publicKey: derivedHdkey.publicKey,
privateKey,
publicKey,
};
};

Expand Down Expand Up @@ -67,3 +59,38 @@ export const deriveHDKeyFromEthereumSignature = (
const entropy = keccak256(rsValues);
return exportMnemonicAndPrivateKey(entropy);
};

/**
* @description Derive priv/pub keys from mnemonic and BIP44 HD path
*
* @url https://github.com/confio/cosmos-hd-key-derivation-spec#bip44
*
* @param mnemonic used to generate seed
*
* @param path BIP44 HD Path. Default is The Cosmos Hub path
*
* @throws Error if the hdkey does not exist
*
* @returns Priv/pub keys
*/
export const deriveHDKeyFromMnemonic = (
mnemonic: string,
path: string = "m/44'/118'/0'/0/0",
): {
privateKey: Uint8Array | null;
publicKey: Uint8Array | null;
} => {
const seed = mnemonicToSeedSync(mnemonic);

const hdkey = HDKey.fromMasterSeed(seed);
const derivedHdkey = hdkey.derive(path);

if (!hdkey.privateKey) {
throw new Error('null hd key');
}

return {
privateKey: derivedHdkey.privateKey,
publicKey: derivedHdkey.publicKey,
};
};

0 comments on commit 5ff27c0

Please sign in to comment.