Skip to content

Commit

Permalink
evm create transaction rpc (#5242)
Browse files Browse the repository at this point in the history
  • Loading branch information
jowparks committed Aug 13, 2024
1 parent dc473a7 commit e347153
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -1060,5 +1060,113 @@
}
]
}
],
"Route wallet/createTransaction should generate a valid transaction with EVM description": [
{
"value": {
"version": 4,
"id": "ecfdb63b-d264-4fb9-9d05-6a405f77d3ae",
"name": "existingAccount",
"spendingKey": "0f7f735d6429d77890ccd030456fa06b000eb99ea280ed7be26ccbe91cb5a701",
"viewKey": "1cbdc5d4351d73a3a18c05ed77f6dd43635b7ba5b0aad5d9e4303cc8aac6d2d552d217e9f9090a175a864e438a743cd2f134cc192d11502d0a67728ecc0755c4",
"incomingViewKey": "b130e2f19e0ba894d09ed31f62d1ce20741440a611453fe63e30c67dbfe1b605",
"outgoingViewKey": "ac850bc3411e50bb664411029eb3baabfffd5898bb30c30d11996bb454ab6330",
"publicAddress": "0b74a0b2f65349a44497d6cd155c656ec621bf5ab0aef6fc99d1f08cf1109deb",
"createdAt": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
},
"scanningEnabled": true,
"proofAuthorizingKey": "a11c99d533a1dc27355135fbdede47746612e62d6c8000b0b97f11bb94ea380b"
},
"head": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
}
},
{
"header": {
"sequence": 2,
"previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86",
"noteCommitment": {
"type": "Buffer",
"data": "base64:RxOyZDvVy6f0auHJrHAag49ziyNHsIuwpMCFab6/YDs="
},
"transactionCommitment": {
"type": "Buffer",
"data": "base64:AtEe3j8aJqnKNpg8CGUKjIOibOHM+DCB9AX/9Z6CNBA="
},
"target": "9282972777491357380673661573939192202192629606981189395159182914949423",
"randomness": "0",
"timestamp": 1723568831818,
"graffiti": "0000000000000000000000000000000000000000000000000000000000000000",
"noteSize": 4,
"work": "0"
},
"transactions": [
{
"type": "Buffer",
"data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAP8V6q1BQrywYZIbwdFc3voqd2ND0BdAG8G68Rgdlvqyrlbe4ZOujI7Pzi6nv32POD4xnuF2iYtEzzUCvhgFfp9ZHFXcs12M0RWvVrSWvKqaC2cyFQ1j2ShIR52YN1l2OIlJXKvM52GJhIQd/m55B5zuSawSfvm++WTiEzI9ImXUFfP5F+hVzzyzGZTT2njxBp0xtBLuZTla3I6yzP4jVhds11yWVJWrYiBDq4WZvuFa1+zFqjmj8BUU06fRSLbNNmZFGhZ/ux3SynrrCZcm03rm9IyJxQCG7lzOG8+3XQvKgbnqohI4LV/iHDdk2+v3inTpjKWLmjtATa8m7wekmB3BLAPV7L/HDcCboNYkH7m2rKHiOEfFNvTLZIdhXCJVnlcf/YMpUQZlZTzspLZ6ldvHUIg7jKhPTNCterQ11h8Yb3WXrwFAXFmV6eXFiq0LriWCoXcMtlnM47feZKyEDsznWFaBYadeAXVRVWka4C3AmM3ednKkfROTtarXUWj9KS8mD/HIb4SCHmm5JlBXJG+IsjegW7a8qlFKlhQC1+KiMhHgsPxgG6nLjdLr5/QLWWTrhFqO4qKG1PkDhpYmPJ8ra1FLPgBNTW6W46tNfdRvc2h8eYc1qYklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw7F67Sp1eTOBBGpglBgiRka1arXBgfWvgBAMFsoMyayjgbYrSvWQQVfI6G13ol+sBCyvdOhYuC8iU/XIrC6y6BQ=="
}
]
},
{
"header": {
"sequence": 3,
"previousBlockHash": "F5A70BD9C5474C6380415DDACD90C030DCFE011F40B9F08B326B7920908969E1",
"noteCommitment": {
"type": "Buffer",
"data": "base64:Mr85jsWkZ9ofJ40H3tdCqO7x3kAcJkwQw13C9YmYdEY="
},
"transactionCommitment": {
"type": "Buffer",
"data": "base64:N/BasxMEEzyBeEm1AMr0a1Nce8HcOjJA7NjjRmBvqtw="
},
"target": "9255858786337818395603165512831024101510453493377417362192396248796027",
"randomness": "0",
"timestamp": 1723568832132,
"graffiti": "0000000000000000000000000000000000000000000000000000000000000000",
"noteSize": 5,
"work": "0"
},
"transactions": [
{
"type": "Buffer",
"data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAAx9A7sg8ysWo7L+q8KoUP25gFg30tMlGw7fpIYNEuVmCttpfFGsqe/aUxijXNZWKvlPFnO3xvGEdOLrVjJcRdJ/EYsXAEhpbGpuTzqDcUqGk37MCk7Hv0YjJ4Cpx2V9sYRG4KG2HFqzwps0IanDf0Gnfg2FGebgmQf1Qvm8lkaYDIk8S211CRxrKgbbgky0PGqpQiSvWF2gy8iJIeE/R8utYgjJimVVSvngbo9LeqgyMMB876xvWNsrffM3rt+YyjZXQQSCKlouofJdionftmhgyxsdZC+owuyfBJ5a7n90lZi3YzGP7NdEFbK4Jbu9AimbbwmIjNOqbb2of4p8OJ8NCbWupU3tifULfS7hhZJAlCb8JYevJIHm59bpdhjcEfOsrDLlg65SmEGuqvOnjjfYPD3hZQO0qzcCAqgLx+jlzSgWKJJbPSzzf1EyLrUEpPJIOIruj4CiqEWNxdm2tQ1htKxHNIb4a9wu5EEaKk/4vLrcw7+M6ElobZjla5hwbxvXRQTWw3CySz+eqYwhbc26uDknskyOVh4YECJk4fyYJd/Wso/bTFVnDdEYHeqolEcg/PXASWzKi8eyQl6mdm7brGQFWE3YK15K1jG1VMhh+MTZDEJhrfklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwwWVMbhdsmW4O06MUYf2qTQ1EEngj8hmN/BpJt1UrbS2nYo1BjQknQE3drqVC7CwSJ2HUY/vyZRJHVcGGk2yMAA=="
}
]
},
{
"header": {
"sequence": 4,
"previousBlockHash": "1988B096DB3C5A6E5878D378AE16B11329D242EE0CCC5BD6E1A52C86D11563C4",
"noteCommitment": {
"type": "Buffer",
"data": "base64:XqDZQY5DcEVXgtxwSUf0n/qcyOS3nABMlst7BHQaJxA="
},
"transactionCommitment": {
"type": "Buffer",
"data": "base64:lsoV7EJOhy0V9Rc2irvFU5iVsvmUc5Pvmztc+ttwhNA="
},
"target": "9228823284279306817296266184515742822248210830185427859262273659833347",
"randomness": "0",
"timestamp": 1723568832443,
"graffiti": "0000000000000000000000000000000000000000000000000000000000000000",
"noteSize": 6,
"work": "0"
},
"transactions": [
{
"type": "Buffer",
"data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAu31EuMR2dhMNlXAmMWYdCjUb1AjUckEHENgDiOsvmeOLtqmPc1h4sOwXcXdBQGjDZcLcUAIodd0FBkMfSlQAax5xRniRarGWe5orgE6QMvCr8HZFoRkZJN/FcfW3uq7q+AH65kZJzUcpSCmUrfgKi90ThXCbZfMZGbdNh3ufLLYO/Z8d2TnKalbs/4qcvJLvp7hgRUswoTnYJbMcFVoYir/ZdIOeTJA6eeqKjsbmf4yyTFMW4+tdk0Ta6/mYAllgxxHU41KxiFJMKwXn+bJq5cctZlld9CM5guHq9GnHPeeym2OfZAtFsExcVLuq5fzZJf8bpcXnufYuaq4SGfsR5AVkSD+u5h6s/OckC5V+9FJdxKe/1e/Fw9jv0OZq5zY9RRCanKXZziVp1JIT4lF8cF5qttqPFM34ETgiBy6AFPAg1OfDCmdb0VcMgMBaRxNkfCW6L8w/YSDAWlrUunxOlvUeZxfobp5bWMeRIKuLHjzH4oVdZaNMWT1lbIm4uLyVg3KrPw4P0E9sbgKrjgFA+vdMxLkjYj6IRQK8roVuWU8hd8Cbupsh0XEi2xQ4b48j5431vnu2hkz/hYpK0xdjZzvFmCS+9vEE9HXGJPm3oVxuZ3FD7EaqMElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwHDLNZab/s/9JQKP/lUH4Q5ffyjaKtmkGNzDn3BtXKnLGU4IPo8NAnY080XleZPx9qjxIdf0VH8N+tVaVh2CsBQ=="
}
]
}
]
}
61 changes: 61 additions & 0 deletions ironfish/src/rpc/routes/wallet/createTransaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

import { Asset, MEMO_LENGTH } from '@ironfish/rust-nodejs'
import { Assert } from '../../../assert'
import { Consensus } from '../../../consensus'
import { TransactionVersion } from '../../../primitives'
import { RawTransactionSerde } from '../../../primitives/rawTransaction'
import { useAccountFixture, useMinerBlockFixture } from '../../../testUtilities'
import { createRouteTest } from '../../../testUtilities/routeTest'
Expand Down Expand Up @@ -168,6 +171,64 @@ describe('Route wallet/createTransaction', () => {
expect(rawTransaction.fee).toBeGreaterThan(0n)
})

it('should generate a valid transaction with EVM description', async () => {
const sender = await useAccountFixture(routeTest.node.wallet, 'existingAccount')

for (let i = 0; i < 3; ++i) {
const block = await useMinerBlockFixture(
routeTest.chain,
undefined,
sender,
routeTest.node.wallet,
)

await expect(routeTest.node.chain).toAddBlock(block)

await routeTest.node.wallet.scan()
}

const mockGetActiveTransactionVersion = jest
.spyOn(Consensus.prototype, 'getActiveTransactionVersion')
.mockImplementation(() => TransactionVersion.V3)

const response = await routeTest.client.wallet.createTransaction({
account: 'existingAccount',
outputs: [],
evm: {
nonce: '1',
gasPrice: '20000000000',
gasLimit: '21000',
to: 'b794f5ea0ba39494ce839613fffba74279579268',
value: '1000000000000000000',
data: '0x',
privateIron: '0',
publicIron: '0',
},
fee: undefined,
feeRate: '200',
})

expect(response.status).toBe(200)
expect(response.content.transaction).toBeDefined()

const rawTransactionBytes = Buffer.from(response.content.transaction, 'hex')
const rawTransaction = RawTransactionSerde.deserialize(rawTransactionBytes)

expect(rawTransaction.evm).toBeDefined()
Assert.isNotNull(rawTransaction.evm)
expect(rawTransaction.evm.nonce).toBe(BigInt(1))
expect(rawTransaction.evm.gasPrice).toBe(BigInt(20000000000))
expect(rawTransaction.evm.gasLimit).toBe(BigInt(21000))
expect(rawTransaction.evm.to.toString('hex')).toBe(
'b794f5ea0ba39494ce839613fffba74279579268',
)
expect(rawTransaction.evm.value).toBe(BigInt(1000000000000000000))
expect(rawTransaction.evm.data.toString('hex')).toBe('')
expect(rawTransaction.evm.privateIron).toBe(BigInt(0))
expect(rawTransaction.evm.publicIron).toBe(BigInt(0))
mockGetActiveTransactionVersion.mockRestore()
})

it('should create transaction if fee and fee rate are empty', async () => {
const sender = await useAccountFixture(routeTest.node.wallet, 'existingAccount')

Expand Down
53 changes: 52 additions & 1 deletion ironfish/src/rpc/routes/wallet/createTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import * as yup from 'yup'
import { Assert } from '../../../assert'
import { RawTransactionSerde } from '../../../primitives/rawTransaction'
import { CurrencyUtils, YupUtils } from '../../../utils'
import { CurrencyUtils, EthUtils, YupUtils } from '../../../utils'
import { Wallet } from '../../../wallet'
import { NotEnoughFundsError } from '../../../wallet/errors'
import { RPC_ERROR_CODES, RpcValidationError } from '../../adapters/errors'
Expand Down Expand Up @@ -39,6 +39,19 @@ export type CreateTransactionRequest = {
assetId: string
value: string
}[]
evm?: {
nonce: string
gasPrice: string
gasLimit: string
to: string
value: string
data: string
privateIron: string
publicIron: string
v?: string
r?: string
s?: string
}
fee?: string | null
feeRate?: string | null
expiration?: number
Expand Down Expand Up @@ -93,6 +106,22 @@ export const CreateTransactionRequestSchema: yup.ObjectSchema<CreateTransactionR
.defined(),
)
.optional(),
evm: yup
.object({
nonce: yup.string().defined(),
gasPrice: yup.string().defined(),
gasLimit: yup.string().defined(),
to: yup.string().defined(),
value: yup.string().defined(),
data: yup.string().defined(),
publicIron: yup.string().defined(),
privateIron: yup.string().defined(),
v: yup.string(),
r: yup.string(),
s: yup.string(),
})
.optional()
.default(undefined),
fee: YupUtils.currency({ min: 1n }).nullable().optional(),
feeRate: YupUtils.currency({ min: 1n }).nullable().optional(),
expiration: yup.number().optional(),
Expand Down Expand Up @@ -218,6 +247,28 @@ routes.register<typeof CreateTransactionRequestSchema, CreateTransactionResponse
}
}

if (request.data.evm) {
// if 0x is present, remove it
const evm = request.data.evm
const to = EthUtils.remove0x(evm.to)
const data = EthUtils.remove0x(evm.data)
const r = evm.r ? EthUtils.remove0x(evm.r) : undefined
const s = evm.s ? EthUtils.remove0x(evm.s) : undefined
params.evm = {
nonce: BigInt(evm.nonce),
gasPrice: BigInt(evm.gasPrice),
gasLimit: BigInt(evm.gasLimit),
to: Buffer.from(to, 'hex'),
value: BigInt(evm.value),
data: Buffer.from(data, 'hex'),
privateIron: BigInt(evm.privateIron),
publicIron: BigInt(evm.publicIron),
v: evm.v ? BigInt(evm.v) : undefined,
r: r ? Buffer.from(r, 'hex') : undefined,
s: s ? Buffer.from(s, 'hex') : undefined,
}
}

try {
const transaction = await node.wallet.createTransaction(params)
const serialized = RawTransactionSerde.serialize(transaction)
Expand Down
13 changes: 13 additions & 0 deletions ironfish/src/utils/eth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

function prefix0x(data: string): string {
return data.startsWith('0x') ? data : `0x${data}`
}

function remove0x(data: string): string {
return data.startsWith('0x') ? data.slice(2) : data
}

export const EthUtils = { prefix0x, remove0x }
1 change: 1 addition & 0 deletions ironfish/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './compactblock'
export * from './currency'
export * from './enums'
export * from './error'
export * from './eth'
export * from './file'
export * from './decimalUtils'
export * from './graffiti'
Expand Down

0 comments on commit e347153

Please sign in to comment.