Skip to content
This repository has been archived by the owner on Oct 13, 2023. It is now read-only.

Commit

Permalink
test: add e2e test for EIP712 legacy TypedData (#154)
Browse files Browse the repository at this point in the history
  • Loading branch information
0a1c committed Mar 23, 2023
1 parent 76ea63e commit 753cbdf
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 93 deletions.
68 changes: 30 additions & 38 deletions package-lock.json

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

1 change: 1 addition & 0 deletions packages/evmosjs/package-lock.json

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

1 change: 1 addition & 0 deletions packages/evmosjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"devDependencies": {
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
"@ethersproject/hash": "^5.7.0",
"@ethersproject/keccak256": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@ethersproject/wallet": "^5.7.0",
Expand Down
9 changes: 8 additions & 1 deletion packages/evmosjs/src/tests/network.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@ describe('evmosjs e2e integration tests', () => {
expectSuccess(response)
})

it('fulfills legacy eip-712 signatures', async () => {
const response = await networkClient.signEIP712AndBroadcast(
MsgSendUtils.generateTx,
)
expectSuccess(response)
})

it('fulfills msgconverterc20 transactions', async () => {
const client = new ConvertCoinClient(networkClient)
await client.testIntegration()
}, 30000)
}, 36000)
})
9 changes: 2 additions & 7 deletions packages/evmosjs/src/tests/network/broadcast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@ import {
generateEndpointBroadcast,
generatePostBodyBroadcast,
} from '@evmos/provider'
import { Proto } from '@evmos/proto'
import fetch from 'node-fetch'
import { nodeUrl } from './params.js'

interface SignedTx {
message: Proto.Cosmos.Transactions.Tx.TxRaw
path: string
}
import { nodeUrl } from './params'
import { SignedTx } from './types'

export const broadcastTx = async (signedTx: SignedTx) => {
const postOptions = {
Expand Down
27 changes: 14 additions & 13 deletions packages/evmosjs/src/tests/network/client.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import secp256k1 from 'secp256k1'
import { TxContext, TxPayload } from '@evmos/transactions'
import { fetchSenderInfo } from './query'
import { createTxContext } from './payload'
import { signDirect } from './sign'
import { signDirect, signEIP712 } from './sign'
import { broadcastTx } from './broadcast'
import { wallet } from './params'

export interface TxResponse {
// eslint-disable-next-line camelcase
tx_response: {
code: number
txhash: string
}
}

export type CreatePayloadFn = (context: TxContext) => TxPayload
import { TxResponse, CreatePayloadFn, SignPayloadFn } from './types'

class NetworkTestClient {
private nonce: number | undefined

signDirectAndBroadcast = async (createTxPayload: CreatePayloadFn) => {
return this.signAndBroadcast(createTxPayload, signDirect)
}

signEIP712AndBroadcast = async (createTxPayload: CreatePayloadFn) => {
return this.signAndBroadcast(createTxPayload, signEIP712)
}

private signAndBroadcast = async (
createTxPayload: CreatePayloadFn,
signPayload: SignPayloadFn,
) => {
const context = await this.createTxContext()
const payload = createTxPayload(context)

const signedTx = await signDirect(payload)
const signedTx = await signPayload(payload)
const response = await broadcastTx(signedTx)

console.log(response)
Expand Down
7 changes: 6 additions & 1 deletion packages/evmosjs/src/tests/network/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TxResponse } from './client'
import { TxResponse } from './types'

export const expectSuccess = (response: TxResponse) => {
// eslint-disable-next-line camelcase
Expand All @@ -7,3 +7,8 @@ export const expectSuccess = (response: TxResponse) => {

export const delay = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms))

export const hexToBytes = (hex: string) =>
Buffer.from(hex.replace('0x', ''), 'hex')

export const base64ToBytes = (base64: string) => Buffer.from(base64, 'base64')
62 changes: 62 additions & 0 deletions packages/evmosjs/src/tests/network/eip712.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { _TypedDataEncoder as TypedDataEncoder } from '@ethersproject/hash'
import { keccak256 } from '@ethersproject/keccak256'
import { EIP712ToSign } from '@evmos/transactions'
import { hexToBytes } from './common'

type EIP712Types = Record<string, { name: string; type: string }[]>
type EIP712Domain = Record<string, number | string>
type EIP712Message = Record<string, unknown>

const hashDomain = (payload: {
types: EIP712Types
domain: EIP712Domain
}): string =>
TypedDataEncoder.hashStruct(
'EIP712Domain',
{ EIP712Domain: payload.types.EIP712Domain },
payload.domain,
)

const hashMessage = (payload: {
types: EIP712Types
primaryType: string
message: EIP712Message
}): string =>
TypedDataEncoder.from(
(() => {
const types = { ...payload.types }
delete types.EIP712Domain

// EthersJS assumes the first type is the primary type
const primary = types[payload.primaryType]
if (!primary) {
throw new Error(`No matched primary type: ${payload.primaryType}`)
}
delete types[payload.primaryType]

return {
[payload.primaryType]: primary,
...types,
}
})(),
).hash(payload.message)

export const eip712Digest = (payload: EIP712ToSign) => {
const typedPayload = payload as {
types: EIP712Types
primaryType: string
domain: EIP712Domain
message: EIP712Message
}

const raw = Buffer.concat([
Buffer.from('19', 'hex'),
Buffer.from('01', 'hex'),
hexToBytes(hashDomain(typedPayload)),
hexToBytes(hashMessage(typedPayload)),
])

const hashAsHex = keccak256(raw)

return hexToBytes(hashAsHex)
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ConvertCoinIntegrationClient extends NetworkClientHost {
expectSuccess(response)

// Wait for state changes to propogate to API
await delay(15000)
await delay(21000)

// Verify state changes for each client.
await proposalClient.verifyStateChange()
Expand Down
Loading

0 comments on commit 753cbdf

Please sign in to comment.