Skip to content

Commit c74807a

Browse files
committed
fix: also export item types
1 parent 6b7040b commit c74807a

File tree

2 files changed

+93
-89
lines changed

2 files changed

+93
-89
lines changed

src/encoder.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import BN from 'bn.js'
2+
import * as RLP from 'rlp'
3+
import { toUtf8String, getAddress } from 'ethers/utils'
4+
import { solidityTypes, typeToSolidity } from './item-types'
5+
6+
interface Column {
7+
type: string;
8+
label: string;
9+
}
10+
11+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
12+
13+
const bufferToHex = (buf: Buffer) => {
14+
const bufferString = buf.toString('hex')
15+
16+
if (bufferString.substring(0, 2) === '0x') return bufferString
17+
return `0x${bufferString}`
18+
}
19+
20+
const MAX_SIGNED_INTEGER = new BN(1).iushln(255).sub(new BN(1)) // int(~(uint(1) << 255))
21+
const MIN_SIGNED_INTEGER = new BN(1).iushln(255).neg() // int(uint(1) << 255)
22+
23+
export const gtcrEncode = ({ columns, values }: { columns: Column[], [values: string]: any }) => {
24+
const itemArr = columns.map(col => {
25+
switch (typeToSolidity[col.type]) {
26+
case solidityTypes.STRING:
27+
return values[col.label] || ''
28+
case solidityTypes.INT256: {
29+
if (new BN(values[col.label]).gt(MAX_SIGNED_INTEGER)) { throw new Error('Number exceeds maximum supported signed integer.') }
30+
if (new BN(values[col.label]).lt(MIN_SIGNED_INTEGER)) {
31+
throw new Error(
32+
'Number smaller than minimum supported signed integer.'
33+
)
34+
}
35+
return new BN(values[col.label] || '0').toTwos(256) // Two's complement
36+
}
37+
case solidityTypes.ADDRESS:
38+
return new BN(
39+
values[col.label]
40+
? values[col.label].slice(2)
41+
: ZERO_ADDRESS.slice(2),
42+
16
43+
)
44+
case solidityTypes.BOOL:
45+
return new BN(values[col.label] ? 1 : 0)
46+
default:
47+
throw new Error(`Unhandled item type ${col.type}`)
48+
}
49+
})
50+
51+
return bufferToHex(RLP.encode(itemArr))
52+
}
53+
54+
const padAddr = (rawAddr: string) => `${'0'.repeat(40 - rawAddr.length)}${rawAddr}`
55+
56+
export const gtcrDecode = ({ columns, values }: { columns: Column[], values: any }) => {
57+
const item = RLP.decode(values) as any
58+
return columns.map((col, i) => {
59+
try {
60+
switch (typeToSolidity[col.type]) {
61+
case solidityTypes.STRING: {
62+
try {
63+
return toUtf8String(item[i])
64+
} catch (err) {
65+
// If the string was a hex value, the decoder fails.
66+
// return the raw hex.
67+
if (
68+
err.message ===
69+
'invalid utf8 byte sequence; unexpected continuation byte'
70+
) { return `0x${item[i].toString('hex')}` } else throw err
71+
}
72+
}
73+
case solidityTypes.INT256:
74+
return new BN(item[i], 16).fromTwos(256).toString(10) // Two's complement
75+
case solidityTypes.ADDRESS: {
76+
// If addresses are small, we must left pad them with zeroes
77+
const rawAddr = item[i].toString('hex')
78+
return getAddress(`0x${padAddr(rawAddr)}`)
79+
}
80+
case solidityTypes.BOOL:
81+
return Boolean(new BN(item[i].toString('hex'), 16).toNumber())
82+
default:
83+
throw new Error(`Unhandled item type ${col.type}`)
84+
}
85+
} catch (err) {
86+
console.error(`Error decoding ${col.type}`, err)
87+
return `Error decoding ${col.type}`
88+
}
89+
})
90+
}

src/index.ts

Lines changed: 3 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,4 @@
1-
import BN from 'bn.js'
2-
import * as RLP from 'rlp'
3-
import { toUtf8String, getAddress } from 'ethers/utils'
4-
import { solidityTypes, typeToSolidity } from './item-types'
1+
import ItemTypes from './item-types'
2+
import { gtcrEncode, gtcrDecode } from './encoder'
53

6-
interface Column {
7-
type: string;
8-
label: string;
9-
}
10-
11-
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
12-
13-
const bufferToHex = (buf: Buffer) => {
14-
const bufferString = buf.toString('hex')
15-
16-
if (bufferString.substring(0, 2) === '0x') return bufferString
17-
return `0x${bufferString}`
18-
}
19-
20-
const MAX_SIGNED_INTEGER = new BN(1).iushln(255).sub(new BN(1)) // int(~(uint(1) << 255))
21-
const MIN_SIGNED_INTEGER = new BN(1).iushln(255).neg() // int(uint(1) << 255)
22-
23-
export const gtcrEncode = ({ columns, values }: { columns: Column[], [values: string]: any }) => {
24-
const itemArr = columns.map(col => {
25-
switch (typeToSolidity[col.type]) {
26-
case solidityTypes.STRING:
27-
return values[col.label] || ''
28-
case solidityTypes.INT256: {
29-
if (new BN(values[col.label]).gt(MAX_SIGNED_INTEGER)) { throw new Error('Number exceeds maximum supported signed integer.') }
30-
if (new BN(values[col.label]).lt(MIN_SIGNED_INTEGER)) {
31-
throw new Error(
32-
'Number smaller than minimum supported signed integer.'
33-
)
34-
}
35-
return new BN(values[col.label] || '0').toTwos(256) // Two's complement
36-
}
37-
case solidityTypes.ADDRESS:
38-
return new BN(
39-
values[col.label]
40-
? values[col.label].slice(2)
41-
: ZERO_ADDRESS.slice(2),
42-
16
43-
)
44-
case solidityTypes.BOOL:
45-
return new BN(values[col.label] ? 1 : 0)
46-
default:
47-
throw new Error(`Unhandled item type ${col.type}`)
48-
}
49-
})
50-
51-
return bufferToHex(RLP.encode(itemArr))
52-
}
53-
54-
const padAddr = (rawAddr: string) => `${'0'.repeat(40 - rawAddr.length)}${rawAddr}`
55-
56-
export const gtcrDecode = ({ columns, values }: { columns: Column[], values: any }) => {
57-
const item = RLP.decode(values) as any
58-
return columns.map((col, i) => {
59-
try {
60-
switch (typeToSolidity[col.type]) {
61-
case solidityTypes.STRING: {
62-
try {
63-
return toUtf8String(item[i])
64-
} catch (err) {
65-
// If the string was a hex value, the decoder fails.
66-
// return the raw hex.
67-
if (
68-
err.message ===
69-
'invalid utf8 byte sequence; unexpected continuation byte'
70-
) { return `0x${item[i].toString('hex')}` } else throw err
71-
}
72-
}
73-
case solidityTypes.INT256:
74-
return new BN(item[i], 16).fromTwos(256).toString(10) // Two's complement
75-
case solidityTypes.ADDRESS: {
76-
// If addresses are small, we must left pad them with zeroes
77-
const rawAddr = item[i].toString('hex')
78-
return getAddress(`0x${padAddr(rawAddr)}`)
79-
}
80-
case solidityTypes.BOOL:
81-
return Boolean(new BN(item[i].toString('hex'), 16).toNumber())
82-
default:
83-
throw new Error(`Unhandled item type ${col.type}`)
84-
}
85-
} catch (err) {
86-
console.error(`Error decoding ${col.type}`, err)
87-
return `Error decoding ${col.type}`
88-
}
89-
})
90-
}
4+
export { ItemTypes, gtcrEncode, gtcrDecode }

0 commit comments

Comments
 (0)