| 
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'  | 
5 | 3 | 
 
  | 
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