ox
Version:
Ethereum Standard Library
549 lines (492 loc) • 26.8 kB
text/typescript
import { Execute } from 'ox/erc7821'
import { describe, expect, test } from 'vp/test'
describe('encodeData', () => {
test('default', () => {
expect(
Execute.encodeData([
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 2n,
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c530100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: single call', () => {
expect(
Execute.encodeData([
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1000000000000000000n,
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c53010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cafebabecafebabecafebabecafebabecafebabe0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: no data', () => {
expect(
Execute.encodeData([
{
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
{
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 2n,
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c5301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: no value', () => {
expect(
Execute.encodeData([
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
},
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c530100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: empty calls array', () => {
expect(Execute.encodeData([])).toMatchInlineSnapshot(
`"0xe9ae5c5301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: with opData', () => {
expect(
Execute.encodeData(
[
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
],
{ opData: '0x1234567890abcdef' },
),
).toMatchInlineSnapshot(
`"0xe9ae5c530100000000007821000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081234567890abcdef000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: with empty opData', () => {
expect(
Execute.encodeData(
[
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
],
{ opData: '0x' },
),
).toMatchInlineSnapshot(
`"0xe9ae5c530100000000007821000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: mixed calls with and without data/value', () => {
expect(
Execute.encodeData([
{
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 100n,
},
{
data: '0xdeadbeef',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
},
{
data: '0xcafebabe',
to: '0x1234567890123456789012345678901234567890',
value: 200n,
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c5301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000180000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000000000000000000000000000123456789012345678901234567890123456789000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000"`,
)
})
})
describe('decodeData', () => {
test('default', () => {
const calls = [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 2n,
},
] as const
const encoded = Execute.encodeData(calls)
const result = Execute.decodeData(encoded)
expect(result).toEqual({ calls })
})
test('behavior: single call', () => {
const calls = [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1000000000000000000n,
},
] as const
const encoded = Execute.encodeData(calls)
const result = Execute.decodeData(encoded)
expect(result).toEqual({ calls })
})
test('behavior: empty calls', () => {
const calls = [] as const
const encoded = Execute.encodeData(calls)
const result = Execute.decodeData(encoded)
expect(result).toEqual({ calls })
})
test('behavior: with opData', () => {
const calls = [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
] as const
const opData = '0x1234567890abcdef' as const
const encoded = Execute.encodeData(calls, { opData })
const result = Execute.decodeData(encoded)
expect(result).toEqual({ calls, opData })
})
test('behavior: with empty opData', () => {
const calls = [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
] as const
const opData = '0x' as const
const encoded = Execute.encodeData(calls, { opData })
const result = Execute.decodeData(encoded)
expect(result).toEqual({
calls,
opData: undefined,
})
})
test('behavior: no data or value', () => {
const calls = [
{
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 0n,
data: '0x',
},
] as const
const encoded = Execute.encodeData(calls)
const result = Execute.decodeData(encoded)
expect(result).toEqual({ calls })
})
test('behavior: round trip with mixed calls', () => {
const calls = [
{
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 100n,
data: '0x',
},
{
data: '0xdeadbeef',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 0n,
},
{
data: '0xcafebabe',
to: '0x1234567890123456789012345678901234567890',
value: 200n,
},
] as const
const encoded = Execute.encodeData(calls)
const result = Execute.decodeData(encoded)
expect(result).toEqual({ calls })
})
})
describe('encodeBatchOfBatchesData', () => {
test('default', () => {
expect(
Execute.encodeBatchOfBatchesData([
{
calls: [
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 1n,
},
],
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 2n,
},
],
opData: '0x1234567890abcdef',
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c5301000000000078210002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004cafebabe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081234567890abcdef000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: single batch', () => {
expect(
Execute.encodeBatchOfBatchesData([
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
],
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c530100000000007821000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: batch without opData', () => {
expect(
Execute.encodeBatchOfBatchesData([
{
calls: [
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 1n,
},
],
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 2n,
},
],
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c530100000000007821000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004cafebabe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: batch with empty opData', () => {
expect(
Execute.encodeBatchOfBatchesData([
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
],
opData: '0x',
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c530100000000007821000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: multiple calls per batch', () => {
expect(
Execute.encodeBatchOfBatchesData([
{
calls: [
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 1n,
},
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 2n,
},
],
},
]),
).toMatchInlineSnapshot(
`"0xe9ae5c5301000000000078210002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004cafebabe00000000000000000000000000000000000000000000000000000000000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"`,
)
})
test('behavior: empty batches array', () => {
expect(Execute.encodeBatchOfBatchesData([])).toMatchInlineSnapshot(
`"0xe9ae5c5301000000000078210002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"`,
)
})
})
describe('decodeBatchOfBatchesData', () => {
test('default', () => {
const batches = [
{
calls: [
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 1n,
},
],
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 2n,
},
],
opData: '0x1234567890abcdef',
},
] as const
const encoded = Execute.encodeBatchOfBatchesData(batches)
const result = Execute.decodeBatchOfBatchesData(encoded)
expect(result).toEqual(batches)
})
test('behavior: single batch', () => {
const batches = [
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
],
},
] as const
const encoded = Execute.encodeBatchOfBatchesData(batches)
const result = Execute.decodeBatchOfBatchesData(encoded)
expect(result).toEqual(batches)
})
test('behavior: batch without opData', () => {
const batches = [
{
calls: [
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 1n,
},
],
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 2n,
},
],
},
] as const
const encoded = Execute.encodeBatchOfBatchesData(batches)
const result = Execute.decodeBatchOfBatchesData(encoded)
expect(result).toEqual(batches)
})
test('behavior: batch with empty opData', () => {
const batches = [
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 1n,
},
],
},
] as const
const opData = '0x' as const
const encoded = Execute.encodeBatchOfBatchesData([
{ calls: batches[0].calls, opData },
])
const result = Execute.decodeBatchOfBatchesData(encoded)
expect(result).toEqual(batches)
})
test('behavior: multiple calls per batch', () => {
const batches = [
{
calls: [
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 1n,
},
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 2n,
},
],
},
] as const
const encoded = Execute.encodeBatchOfBatchesData(batches)
const result = Execute.decodeBatchOfBatchesData(encoded)
expect(result).toEqual(batches)
})
test('behavior: empty batches', () => {
const batches = [] as const
const encoded = Execute.encodeBatchOfBatchesData(batches)
const result = Execute.decodeBatchOfBatchesData(encoded)
expect(result).toEqual(batches)
})
test('behavior: mixed batches with and without opData', () => {
const batches = [
{
calls: [
{
data: '0xcafebabe',
to: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
value: 100n,
},
],
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
value: 200n,
},
],
opData: '0xabcdef',
},
{
calls: [
{
to: '0x1234567890123456789012345678901234567890',
value: 300n,
data: '0x',
},
],
},
] as const
const encoded = Execute.encodeBatchOfBatchesData(batches)
const result = Execute.decodeBatchOfBatchesData(encoded)
expect(result).toEqual(batches)
})
})