1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import fs from 'fs'
import crypto from 'crypto'
interface ForgeTransaction {
contractAddress: string
transaction: {
to: string
value: string
input: string
}
}
interface ForgeTransactionFile {
transactions: ForgeTransaction[]
timestamp: number
chain: number
}
interface SafeTransaction {
to: string
value: string
data: string
contractMethod: null
contractInputsValues: null
}
interface SafeTransactionFile {
version: string
chainId: string
createdAt: number
meta: {
name: string
description: string
txBuilderVersion: string
createdFromSafeAddress: string
createdFromOwnerAddress: string
checksum: string
}
transactions: SafeTransaction[]
}
/**
* Calculate the checksum for a safe transaction file.
* @param data The safe transaction file.
* @returns The checksum.
*/
const checksum = (data: SafeTransactionFile): string => {
const hash = crypto.createHash('sha256')
hash.update(JSON.stringify(data.transactions))
return `0x${hash.digest('hex')}`
}
/**
* Transform a forge transaction file into a safe transaction file.
* @param forge Forge transaction file.
* @param address Safe address.
* @returns Safe transaction file.
*/
const transform = (
forge: ForgeTransactionFile,
address: string
): SafeTransactionFile => {
const transactions = forge.transactions.map((tx) => ({
to: tx.contractAddress,
value: '0',
data: tx.transaction.input,
contractMethod: null,
contractInputsValues: null,
}))
const safe: SafeTransactionFile = {
version: '1.0',
chainId: forge.chain.toString(),
createdAt: forge.timestamp,
meta: {
name: 'Transactions Batch',
description: '',
txBuilderVersion: '1.16.5',
createdFromSafeAddress: address,
createdFromOwnerAddress: '',
checksum: '',
},
transactions,
}
safe.meta.checksum = checksum(safe)
return safe
}
/**
* Get a required argument from the command line.
* @param name The argument name.
* @returns The argument value.
*/
const reqarg = (name: string) => {
const value = process.argv.find((arg) => arg.startsWith(`--${name}=`))
if (!value) {
console.error(`Please provide --${name} argument`)
process.exit(1)
}
return value.split('=')[1]
}
/**
* Main function.
*/
const main = () => {
const input = reqarg('input')
const output = reqarg('output')
const address = reqarg('safe')
// Load the original forge transaction file.
const forge: ForgeTransactionFile = JSON.parse(fs.readFileSync(input, 'utf8'))
// Transform the forge transaction file into a safe transaction file.
const safe = transform(forge, address)
// Write the safe transaction file.
fs.writeFileSync(output, JSON.stringify(safe, null, 2), 'utf8')
}
// Run the main function.
main()