Skip to content
This repository has been archived by the owner on Jun 17, 2021. It is now read-only.

Add toBuffer() method to Address, make toBuffer() function convert TransformableToBuffer #277

Merged
merged 7 commits into from
Oct 7, 2020
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ A new file with helpful TypeScript types has been added to the exports of this p

In this release it contains `BNLike`, `BufferLike`, and `TransformableToBuffer`.

### Address.toBuffer()

The Address class has as a new method `address.toBuffer()` that will give you a copy of the underlying `address.buf`.

### `toBuffer()` now converts TransformableToBuffer

The `toBuffer()` exported function now additionally converts any object with a `toBuffer()` method.

## [7.0.5] - 2020-09-09

This release adds a new module `address` - see [README](https://github.com/ethereumjs/ethereumjs-util#modules) -
Expand Down
7 changes: 7 additions & 0 deletions src/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,11 @@ export class Address {
toString(): string {
return '0x' + this.buf.toString('hex')
}

/**
* Returns Buffer representation of address.
*/
toBuffer(): Buffer {
return Buffer.from(this.buf)
}
}
84 changes: 56 additions & 28 deletions src/bytes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as ethjsUtil from 'ethjs-util'
import * as BN from 'bn.js'
import { intToBuffer, stripHexPrefix, padToEven, isHexString, isHexPrefixed } from 'ethjs-util'
import { TransformableToArray, TransformableToBuffer } from './types'
import { assertIsBuffer, assertIsArray, assertIsHexString } from './helpers'

/**
Expand Down Expand Up @@ -86,7 +87,7 @@ export const unpadArray = function(a: number[]): number[] {
*/
export const unpadHexString = function(a: string): string {
assertIsHexString(a)
a = ethjsUtil.stripHexPrefix(a)
a = stripHexPrefix(a)
return stripZeros(a) as string
}

Expand All @@ -105,35 +106,62 @@ const stripZeros = function(a: any): Buffer | number[] | string {
}

/**
* Attempts to turn a value into a `Buffer`. As input it supports `Buffer`, `String`, `Number`, null/undefined, `BN` and other objects with a `toArray()` method.
* Attempts to turn a value into a `Buffer`.
* Inputs supported: `Buffer`, `String`, `Number`, null/undefined, `BN` and other objects with a `toArray()` or `toBuffer()` method.
* @param v the value
*/
export const toBuffer = function(v: any): Buffer {
if (!Buffer.isBuffer(v)) {
if (Array.isArray(v) || v instanceof Uint8Array) {
v = Buffer.from(v as Uint8Array)
} else if (typeof v === 'string') {
if (ethjsUtil.isHexString(v)) {
v = Buffer.from(ethjsUtil.padToEven(ethjsUtil.stripHexPrefix(v)), 'hex')
} else {
throw new Error(
`Cannot convert string to buffer. toBuffer only supports 0x-prefixed hex strings and this string was given: ${v}`,
)
}
} else if (typeof v === 'number') {
v = ethjsUtil.intToBuffer(v)
} else if (v === null || v === undefined) {
v = Buffer.allocUnsafe(0)
} else if (BN.isBN(v)) {
v = v.toArrayLike(Buffer)
} else if (v.toArray) {
// converts a BN to a Buffer
v = Buffer.from(v.toArray())
} else {
throw new Error('invalid type')
export const toBuffer = function(
v:
| string
| number
| BN
| Buffer
| Uint8Array
| number[]
| TransformableToArray
| TransformableToBuffer
| null
| undefined,
): Buffer {
if (v === null || v === undefined) {
return Buffer.allocUnsafe(0)
}

if (Buffer.isBuffer(v)) {
return Buffer.from(v)
}

if (Array.isArray(v) || v instanceof Uint8Array) {
return Buffer.from(v as Uint8Array)
}

if (typeof v === 'string') {
if (!isHexString(v)) {
throw new Error(
`Cannot convert string to buffer. toBuffer only supports 0x-prefixed hex strings and this string was given: ${v}`,
)
}
return Buffer.from(padToEven(stripHexPrefix(v)), 'hex')
}

if (typeof v === 'number') {
return intToBuffer(v)
}
return v

if (BN.isBN(v)) {
return v.toArrayLike(Buffer)
}

if (v.toArray) {
// converts a BN to a Buffer
return Buffer.from(v.toArray())
}

if (v.toBuffer) {
return Buffer.from(v.toBuffer())
}

throw new Error('invalid type')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this refactored and simplified code of the toBuffer method, also highly valuable to have proper input types here now. 😍

}

/**
Expand Down Expand Up @@ -178,7 +206,7 @@ export const addHexPrefix = function(str: string): string {
return str
}

return ethjsUtil.isHexPrefixed(str) ? str : '0x' + str
return isHexPrefixed(str) ? str : '0x' + str
}

/**
Expand Down
9 changes: 9 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,20 @@ export type BufferLike =
*/
export type PrefixedHexString = string

/*
* A type that represents an object that has a `toArray()` method.
*/
export interface TransformableToArray {
toArray(): Uint8Array
toBuffer?(): Buffer
}

/*
* A type that represents an object that has a `toBuffer()` method.
*/
export interface TransformableToBuffer {
toBuffer(): Buffer
toArray?(): Uint8Array
}

/**
Expand Down
8 changes: 8 additions & 0 deletions test/address.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,12 @@ describe('Address', () => {
assert.equal(addr.toString(), result)
}
})

it('should provide a buffer that does not mutate the original address', () => {
const str = '0x2f015c60e0be116b1f0cd534704db9c92118fb6a'
const address = Address.fromString(str)
const addressBuf = address.toBuffer()
addressBuf.fill(0)
assert.equal(address.toString(), str)
})
})
11 changes: 10 additions & 1 deletion test/bytes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as assert from 'assert'
import * as BN from 'bn.js'
import {
Address,
zeros,
zeroAddress,
isZeroAddress,
Expand Down Expand Up @@ -215,7 +216,7 @@ describe('toBuffer', function() {
// 'toArray'
assert.deepEqual(
toBuffer({
toArray: function() {
toArray: function(): any {
return [1]
},
}),
Expand All @@ -224,6 +225,7 @@ describe('toBuffer', function() {
})
it('should fail', function() {
assert.throws(function() {
// @ts-ignore
toBuffer({ test: 1 })
})
})
Expand All @@ -233,6 +235,13 @@ describe('toBuffer', function() {
assert.throws(() => toBuffer(''))
assert.throws(() => toBuffer('0xR'), '0xR')
})

it('should convert a TransformableToBuffer like the Address class (i.e. provides a toBuffer method)', function() {
const str = '0x2f015c60e0be116b1f0cd534704db9c92118fb6a'
const address = Address.fromString(str)
const addressBuf = toBuffer(address)
assert.ok(addressBuf.equals(address.toBuffer()))
})
})

describe('baToJSON', function() {
Expand Down