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

support cloudHSM as signing method #66

Merged
merged 2 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,3 @@ jobs:
env:
CI: true
ALCHEMY_TOKEN: ${{ secrets.ALCHEMY_TOKEN }}
- run: npm run test:goerli
env:
CI: true
ALCHEMY_TOKEN: ${{ secrets.ALCHEMY_TOKEN }}
6 changes: 6 additions & 0 deletions app/mmConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ module.exports = {
*/
WALLET_PRIVATE_KEY: process.env.WALLET_PRIVATE_KEY,

/**
* GoogleCloud KMS keyVersionName, used unless both of SIGNING_URL and WALLET_PRIVATE_KEY are not set.
* Txs or messages are signed by GoogleCloud KMS remotely
*/
WALLET_KEY_VERSION_NAME: process.env.WALLET_KEY_VERSION_NAME,

// AMM
AMMWRAPPER_CONTRACT_ADDRESS: process.env.AMMWRAPPER_CONTRACT_ADDRESS,

Expand Down
2,171 changes: 2,081 additions & 90 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
"hardhat/**/@ethereumjs/tx": "3.5.0"
},
"dependencies": {
"@ethersproject/abstract-signer": "5.7.0",
"@toolchainx/ethers-gcp-kms-signer": "1.0.5",
"@0x/contract-addresses": "^4.11.0",
"@0x/subproviders": "6.0.8",
"@babel/runtime": "7.3.1",
Expand Down
5 changes: 3 additions & 2 deletions src/check/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ export const checkMMSK = async (config: ConfigForStart) => {
} else {
quoter = new QuoteDispatcher(config.HTTP_SERVER_ENDPOINT, QuoterProtocol.HTTP)
}
const wallet = getWallet()
await startUpdater(quoter, wallet.address)
const wallet = await getWallet()
const walletAddress = await wallet.getAddress()
await startUpdater(quoter, walletAddress)

for (let i = 0; i < arr.length; i += 1) {
const item = arr[i]
Expand Down
39 changes: 32 additions & 7 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import * as readlineSync from 'readline-sync'
import { ConfigForStart } from './types'
import { Wallet } from 'ethers'
import { ethers, Wallet } from 'ethers'
import { GcpKmsSignerCredentials, GcpKmsSigner } from '@toolchainx/ethers-gcp-kms-signer'
import { TypedDataSigner } from '@ethersproject/abstract-signer'
import * as path from 'path'

const config = {
EXCHANGE_URL: null,
PROVIDER_URL: null,

WALLET_ADDRESS: null,
WALLET_PRIVATE_KEY: null,
WALLET_KEY_VERSION_NAME: null,
USE_KEYSTORE: true,

WALLET_KEYSTORE: null,
Expand All @@ -30,12 +34,33 @@ const setConfig = (conf: ConfigForStart) => {
return Object.assign(config, conf)
}

const getWallet = () => {
return new Wallet(
config.WALLET_PRIVATE_KEY.startsWith('0x')
? config.WALLET_PRIVATE_KEY
: '0x' + config.WALLET_PRIVATE_KEY
)
const getWallet = async (): Promise<ethers.Signer & TypedDataSigner> => {
if (config.WALLET_PRIVATE_KEY) {
return new Wallet(
config.WALLET_PRIVATE_KEY.startsWith('0x')
? config.WALLET_PRIVATE_KEY
: '0x' + config.WALLET_PRIVATE_KEY
)
} else if (config.WALLET_KEY_VERSION_NAME) {
const signer = new GcpKmsSigner(getKmsCredentials(config.WALLET_KEY_VERSION_NAME))
return signer
} else {
return null
}
}

const getKmsCredentials = (fullVersionedKeyName: string): GcpKmsSignerCredentials => {
if (!fullVersionedKeyName || fullVersionedKeyName.length === 0) {
return null
}
const strSplits = fullVersionedKeyName.split(path.sep)
return {
projectId: strSplits[1],
locationId: strSplits[3],
keyRingId: strSplits[5],
keyId: strSplits[7],
keyVersion: strSplits[9],
}
}

export { config, setConfig, getWallet }
9 changes: 5 additions & 4 deletions src/handler/signOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ export const signOrder = async (ctx) => {
const { chainID, walletType } = ctx
const order = ctx.request.body
const protocol = ctx.request.body.protocol
const signer = getWallet()
const signer = await getWallet()
const signerAddress = await signer.getAddress()
console.log('signer')
console.log(signer)
const config = updaterStack.markerMakerConfigUpdater.cacheResult
Expand All @@ -59,12 +60,12 @@ export const signOrder = async (ctx) => {
switch (protocol) {
case Protocol.PMMV5:
signature =
signer.address.toLowerCase() == order.pmmOrder.makerAddress.toLowerCase()
signerAddress.toLowerCase() == order.pmmOrder.makerAddress.toLowerCase()
? await signPMMV5ByEOA(order.orderSignDigest, signer)
: await signByMMPSigner(order.orderSignDigest, order.userAddr, order.feeFactor, signer)
break
case Protocol.RFQV1:
if (signer.address.toLowerCase() == order.rfqOrder.makerAddr.toLowerCase()) {
if (signerAddress.toLowerCase() == order.rfqOrder.makerAddr.toLowerCase()) {
const signatureTypedData = await signRFQOrder(
chainID,
config.addressBookV5.RFQ,
Expand Down Expand Up @@ -95,7 +96,7 @@ export const signOrder = async (ctx) => {
}
break
case Protocol.RFQV2:
if (signer.address.toLowerCase() == order.rfqOrder.maker.toLowerCase()) {
if (signerAddress.toLowerCase() == order.rfqOrder.maker.toLowerCase()) {
signature = await signOffer(
chainID,
config.addressBookV5.RFQV2,
Expand Down
14 changes: 8 additions & 6 deletions src/signer/pmmv5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import {
EIP712Types,
} from '0x-v2-order-utils'
import * as ethUtils from 'ethereumjs-util'
import { utils, Wallet } from 'ethers'
import { utils } from 'ethers'
import axios from 'axios'
import { BigNumber, orderBNToString } from '../utils'
import { Protocol } from '../types'
import { ExtendedZXOrder, RemoteSigningPMMV5Request } from './types'
import { Order as ZXOrder } from '0x-v2-order-utils'
import { AbstractSigner } from '@toolchainx/ethers-gcp-kms-signer'

export const EIP712_ORDER_SCHEMA = {
name: 'Order',
Expand Down Expand Up @@ -62,7 +63,7 @@ export const generateSaltWithFeeFactor = (feeFactor: number, prefixSalt?: string
// | V | R | S |userAddr |feeFactor|
// +------|---------|---------|---------|---------+
export async function signWithUserAndFee(
signer: Wallet,
signer: AbstractSigner,
orderSignDigest: string,
userAddr: string,
feeFactor: number
Expand Down Expand Up @@ -92,7 +93,7 @@ export async function signWithUserAndFee(
// +------|---------|---------|---------+
// | v | R | S | type(3) |
// +------|---------|---------|---------+
export async function signByEOA(orderSignDigest: string, wallet: Wallet): Promise<string> {
export async function signByEOA(orderSignDigest: string, wallet: AbstractSigner): Promise<string> {
const hashArray = utils.arrayify(orderSignDigest)
let signature = await wallet.signMessage(hashArray)
signature = signature.slice(2)
Expand All @@ -111,7 +112,7 @@ export async function signByMMPSigner(
orderSignDigest: string,
userAddr: string,
feeFactor: number,
wallet: Wallet
wallet: AbstractSigner
): Promise<string> {
const walletSign = await signWithUserAndFee(wallet, orderSignDigest, userAddr, feeFactor)
return signatureUtils.convertToSignatureWithType(walletSign, SignatureType.Wallet)
Expand All @@ -137,7 +138,7 @@ export const forwardUnsignedOrder = async (

// Move fee factor to salt field
export const buildSignedOrder = async (
signer: Wallet | undefined,
signer: AbstractSigner | undefined,
order: ExtendedZXOrder,
userAddr: string,
chainId: number,
Expand Down Expand Up @@ -179,8 +180,9 @@ export const buildSignedOrder = async (
console.log(`orderSignDigest: ${orderSignDigest}`)
let makerWalletSignature
if (!signingUrl) {
const signerAddress = await signer.getAddress()
makerWalletSignature =
signer.address.toLowerCase() == o.makerAddress.toLowerCase()
signerAddress.toLowerCase() == o.makerAddress.toLowerCase()
? await signByEOA(orderSignDigest, signer)
: await signByMMPSigner(orderSignDigest, userAddr, feeFactor, signer)
} else {
Expand Down
12 changes: 7 additions & 5 deletions src/signer/rfqv1.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Wallet, utils } from 'ethers'
import { utils } from 'ethers'
import { orderBNToString, BigNumber } from '../utils'
import { generateSaltWithFeeFactor, signWithUserAndFee } from './pmmv5'
import { getOrderHash, getOrderSignDigest } from './orderHash'
Expand All @@ -7,6 +7,7 @@ import * as ethUtils from 'ethereumjs-util'
import { SignatureType } from './types'
import axios from 'axios'
import { Protocol } from '../types'
import { AbstractSigner } from '@toolchainx/ethers-gcp-kms-signer'

// spec of RFQV1
// - taker address point to userAddr
Expand All @@ -18,7 +19,7 @@ export async function signByMMPSigner(
orderSignDigest: string,
userAddr: string,
feeFactor: number,
wallet: Wallet,
wallet: AbstractSigner,
walletType: WalletType
): Promise<string> {
if (walletType === WalletType.MMP_VERSION_4) {
Expand Down Expand Up @@ -73,7 +74,7 @@ export const signRFQOrder = async (
chainId: number,
rfqAddr: string,
order: RFQOrder,
maker: Wallet,
maker: AbstractSigner,
feeFactor = 30
): Promise<string> => {
const domain = {
Expand Down Expand Up @@ -117,7 +118,7 @@ export const signRFQOrder = async (
}

export const buildSignedOrder = async (
signer: Wallet | undefined,
signer: AbstractSigner | undefined,
order: ExtendedZXOrder,
userAddr: string,
chainId: number,
Expand Down Expand Up @@ -147,7 +148,8 @@ export const buildSignedOrder = async (
console.log(`orderSignDigest: ${orderSignDigest}`)
let makerWalletSignature
if (!signingUrl) {
if (signer.address.toLowerCase() == order.makerAddress.toLowerCase()) {
const signerAddress = await signer.getAddress()
if (signerAddress.toLowerCase() == order.makerAddress.toLowerCase()) {
const signatureTypedData = await signRFQOrder(
chainId,
rfqAddr,
Expand Down
14 changes: 8 additions & 6 deletions src/signer/rfqv2.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { utils, Wallet } from 'ethers'
import { utils } from 'ethers'
import { orderBNToString } from '../utils'
import { getOfferHash, getOfferSignDigest } from './orderHash'
import {
Expand All @@ -15,6 +15,7 @@ import { generatePseudoRandomSalt } from '0x-v2-order-utils'
import { signWithUserAndFee } from './pmmv5'
import { Protocol } from '../types'
import { BigNumber } from '0x-v2-utils'
import { AbstractSigner } from '@toolchainx/ethers-gcp-kms-signer'

// spec of RFQV2
// - taker address point to userAddr
Expand All @@ -26,7 +27,7 @@ import { BigNumber } from '0x-v2-utils'
// +------|---------|---------|-------------------|---------+
// | R | S | V | reserved 32 bytes | type(3) |
// +------|---------|---------|-------------------|---------+
export async function signByEOA(orderSignDigest: string, wallet: Wallet): Promise<string> {
export async function signByEOA(orderSignDigest: string, wallet: AbstractSigner): Promise<string> {
// signature: R+S+V
const hashArray = utils.arrayify(orderSignDigest)
let signature = await wallet.signMessage(hashArray)
Expand All @@ -43,7 +44,7 @@ export async function signByMMPSigner(
orderSignDigest: string,
userAddr: string,
feeFactor: number,
wallet: Wallet,
wallet: AbstractSigner,
walletType: WalletType
): Promise<string> {
if (walletType === WalletType.MMP_VERSION_4) {
Expand Down Expand Up @@ -98,7 +99,7 @@ export const signOffer = async (
chainId: number,
rfqAddr: string,
order: Offer,
maker: Wallet,
maker: AbstractSigner,
signatureType = SignatureType.EIP712
): Promise<string> => {
const domain = {
Expand Down Expand Up @@ -133,7 +134,7 @@ export const signOffer = async (
}

export const buildSignedOrder = async (
signer: Wallet | undefined,
signer: AbstractSigner | undefined,
order: ExtendedZXOrder,
userAddr: string,
chainId: number,
Expand Down Expand Up @@ -166,7 +167,8 @@ export const buildSignedOrder = async (
console.log(`orderSignDigest: ${orderSignDigest}`)
let makerWalletSignature
if (!signingUrl) {
if (signer.address.toLowerCase() == order.makerAddress.toLowerCase()) {
const signerAddress = await signer.getAddress()
if (signerAddress.toLowerCase() == order.makerAddress.toLowerCase()) {
makerWalletSignature = await signOffer(
chainId,
rfqAddr,
Expand Down
7 changes: 4 additions & 3 deletions src/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,13 @@ export const startMMSK = async (config: ConfigForStart) => {
setConfig(config)
try {
console.log(config.SIGNING_URL)
if (!config.SIGNING_URL) {
wallet = getWallet()
if (!config.SIGNING_URL && config.AMM_ONLY !== 'true') {
wallet = await getWallet()
if (!wallet) {
throw new Error(`Please set either WALLET_PRIVATE_KEY or SIGNING_URL`)
}
if (wallet.address.toLowerCase() != config.WALLET_ADDRESS.toLowerCase()) {
const walletAddress = await wallet.getAddress()
if (walletAddress.toLowerCase() != config.WALLET_ADDRESS.toLowerCase()) {
throw `wallet's address${wallet.address} and ${
config.USE_KEYSTORE ? 'keystore' : 'privateKey'
}(${config.WALLET_ADDRESS}) not matched`
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface ConfigForStart {
EXCHANGE_URL: string
PROVIDER_URL: string
SIGNING_URL: string
AMM_ONLY: string
PERMIT_TYPE: string

WALLET_ADDRESS: string
Expand Down
Loading