forge-to-safe-json.ts 2.74 KB
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()