<commit_before>import Promise = require('bluebird')
import * as util from 'ethereumjs-util'
import { Log } from 'ng2-logger'
import * as configuration from './configuration'
import { FilterResult } from 'web3'
import Web3 = require('web3')
import * as BigNumber from 'bignumber.js'

const log = Log.create('channel')

export interface Signature {
  v: number
  r: Buffer
  s: Buffer
}

export namespace Broker {
  export interface Contract {
    createChannel (receiver: string, duration: number, settlementPeriod: number, options: any, callback: () => void): void
    startSettle (channelId: string, payment: BigNumber.BigNumber, options: any, callback: () => void): void
    claim (channelId: string, value: number, h: string, v: number, r: string, s: string, options: any, callback: () => void): void
    finishSettle (channelId: string, options: any, callback: () => void): void

    canClaim (channelId: string, h: string, v: number, r: string, s: string): boolean
    canStartSettle (account: string, channelId: string, callback: (error: any|null, result?: boolean) => void): void
    canFinishSettle (sender: string, channelId: string): boolean

    getState (channelId: string, callback: (error: any|null, state?: number) => void): void
    getUntil (channelId: string, callback: (error: any|null, until?: number) => void): void

    DidSettle (query: {channelId: string}): FilterResult
    DidStartSettle (query: {channelId: string, payment: BigNumber.BigNumber}): FilterResult
    DidCreateChannel (query: {sender: string, receiver: string}): FilterResult
  }

  export interface DidSettle {
    payment: BigNumber.BigNumber
    channelId: string
    oddValue: BigNumber.BigNumber
  }

  // event DidStartSettle(bytes32 indexed channelId, uint256 payment);
  export interface DidStartSettle {
    channelId: string
    payment: BigNumber.BigNumber
  }

  export interface DidCreateChannel {
    sender: string
    receiver: string
    channelId: string
  }
}

const DAY_IN_SECONDS = 86400

/**
 * Default settlement period for a payment channel
 */
const DEFAULT_SETTLEMENT_PERIOD = 2 * DAY_IN_SECONDS

/**
 * Default duration of a payment channel.
 * @type {number}
 */
const DEFAULT_CHANNEL_TTL = 20 * DAY_IN_SECONDS

/**
 * Cost of creating a channel.
 * @type {number}
 */
const CREATE_CHANNEL_GAS = 300000

const ethHash = (message: string): string => {
  const buffer = Buffer.from('\x19Ethereum Signed Message:\n' + message.length + message)
  return '0x' + util.sha3(buffer).toString('hex')
}

export interface PaymentChannelJSON {
  sender: string
  receiver: string
  channelId: string
  value: number
  spent: number
  state: number
}

/**
 * The Payment Channel
 */
export class PaymentChannel {
  sender: string
  receiver: string
  channelId: string
  value: number
  spent: number
  state: number

  /**
   * @param sender      Ethereum address of the client.
   * @param receiver    Ethereum address of the server.
   * @param channelId   Identifier of the channel.
   * @param value       Total value of the channel.
   * @param spent       Value sent by {sender} to {receiver}.
   * @param state       0 - 'open', 1 - 'settling', 2 - 'settled'
   */
  constructor (sender: string, receiver: string, channelId: string, value: number, spent: number, state: number = 0) { // FIXME remove contract parameter
    this.sender = sender
    this.receiver = receiver
    this.channelId = channelId
    this.value = value
    this.spent = spent
    this.state = state || 0
  }

  static fromPayment (payment: Payment): PaymentChannel {
    return new PaymentChannel(payment.sender, payment.receiver, payment.channelId, payment.channelValue, payment.value)
  }

  static fromDocument (document: PaymentChannelJSON): PaymentChannel {
    return new PaymentChannel(
        document.sender,
        document.receiver,
        document.channelId,
        document.value,
        document.spent,
        document.state
    )
  }

  /**
   * Sign value transfer.
   */
  sign (web3: Web3, value: number): Promise<Signature> {
    const message = this.channelId + value.toString()
    const messageHex = '0x' + Buffer.from(message).toString('hex')

    let isOnNodeJs = true
    /*
    if (typeof BROWSER === 'undefined') {
      isOnNodeJs = true
    }
    */

    if (isOnNodeJs) {
      return new Promise((resolve, reject) => {
        web3.eth.sign(this.sender, messageHex, (error, signature) => {
          if (error) {
            reject(error)
          } else {
            resolve(util.fromRpcSig(signature))
          }
        })
      })
    } else {
      return new Promise((resolve, reject) => {
        const message = Buffer.from(messageHex.replace('0x', ''), 'hex').toString()
        const sha3 = ethHash(message)
        web3.eth.sign(this.sender, sha3, (error, signature) => {
          if (error) {
            reject(error)
          } else {
            resolve(util.fromRpcSig(signature))
          }
        })
      })
    }
  }
}

/**
 * Wrapper for the payment channel contract.
 */
export class ChannelContract {
  web3: Web3
  contract: Broker.Contract

  /**
   * @param web3      Instance of Web3.
   * @param address   Address of the deployed contract.
   * @param abi       Interface of the deployed contract.<commit_msg>Add PaymentChannel#toJSON<commit_after>import Promise = require('bluebird')
import * as util from 'ethereumjs-util'
import { Log } from 'ng2-logger'
import * as configuration from './configuration'
import { FilterResult } from 'web3'
import Web3 = require('web3')
import * as BigNumber from 'bignumber.js'

const log = Log.create('channel')

export interface Signature {
  v: number
  r: Buffer
  s: Buffer
}

export namespace Broker {
  export interface Contract {
    createChannel (receiver: string, duration: number, settlementPeriod: number, options: any, callback: () => void): void
    startSettle (channelId: string, payment: BigNumber.BigNumber, options: any, callback: () => void): void
    claim (channelId: string, value: number, h: string, v: number, r: string, s: string, options: any, callback: () => void): void
    finishSettle (channelId: string, options: any, callback: () => void): void

    canClaim (channelId: string, h: string, v: number, r: string, s: string): boolean
    canStartSettle (account: string, channelId: string, callback: (error: any|null, result?: boolean) => void): void
    canFinishSettle (sender: string, channelId: string): boolean

    getState (channelId: string, callback: (error: any|null, state?: number) => void): void
    getUntil (channelId: string, callback: (error: any|null, until?: number) => void): void

    DidSettle (query: {channelId: string}): FilterResult
    DidStartSettle (query: {channelId: string, payment: BigNumber.BigNumber}): FilterResult
    DidCreateChannel (query: {sender: string, receiver: string}): FilterResult
  }

  export interface DidSettle {
    payment: BigNumber.BigNumber
    channelId: string
    oddValue: BigNumber.BigNumber
  }

  // event DidStartSettle(bytes32 indexed channelId, uint256 payment);
  export interface DidStartSettle {
    channelId: string
    payment: BigNumber.BigNumber
  }

  export interface DidCreateChannel {
    sender: string
    receiver: string
    channelId: string
  }
}

const DAY_IN_SECONDS = 86400

/**
 * Default settlement period for a payment channel
 */
const DEFAULT_SETTLEMENT_PERIOD = 2 * DAY_IN_SECONDS

/**
 * Default duration of a payment channel.
 * @type {number}
 */
const DEFAULT_CHANNEL_TTL = 20 * DAY_IN_SECONDS

/**
 * Cost of creating a channel.
 * @type {number}
 */
const CREATE_CHANNEL_GAS = 300000

const ethHash = (message: string): string => {
  const buffer = Buffer.from('\x19Ethereum Signed Message:\n' + message.length + message)
  return '0x' + util.sha3(buffer).toString('hex')
}

export interface PaymentChannelJSON {
  sender: string
  receiver: string
  channelId: string
  value: number
  spent: number
  state: number
}

/**
 * The Payment Channel
 */
export class PaymentChannel {
  sender: string
  receiver: string
  channelId: string
  value: number
  spent: number
  state: number

  /**
   * @param sender      Ethereum address of the client.
   * @param receiver    Ethereum address of the server.
   * @param channelId   Identifier of the channel.
   * @param value       Total value of the channel.
   * @param spent       Value sent by {sender} to {receiver}.
   * @param state       0 - 'open', 1 - 'settling', 2 - 'settled'
   */
  constructor (sender: string, receiver: string, channelId: string, value: number, spent: number, state: number = 0) { // FIXME remove contract parameter
    this.sender = sender
    this.receiver = receiver
    this.channelId = channelId
    this.value = value
    this.spent = spent
    this.state = state || 0
  }

  static fromPayment (payment: Payment): PaymentChannel {
    return new PaymentChannel(payment.sender, payment.receiver, payment.channelId, payment.channelValue, payment.value)
  }

  static fromDocument (document: PaymentChannelJSON): PaymentChannel {
    return new PaymentChannel(
        document.sender,
        document.receiver,
        document.channelId,
        document.value,
        document.spent,
        document.state
    )
  }

  /**
   * Sign value transfer.
   */
  sign (web3: Web3, value: number): Promise<Signature> {
    const message = this.channelId + value.toString()
    const messageHex = '0x' + Buffer.from(message).toString('hex')

    let isOnNodeJs = true
    /*
    if (typeof BROWSER === 'undefined') {
      isOnNodeJs = true
    }
    */

    if (isOnNodeJs) {
      return new Promise((resolve, reject) => {
        web3.eth.sign(this.sender, messageHex, (error, signature) => {
          if (error) {
            reject(error)
          } else {
            resolve(util.fromRpcSig(signature))
          }
        })
      })
    } else {
      return new Promise((resolve, reject) => {
        const message = Buffer.from(messageHex.replace('0x', ''), 'hex').toString()
        const sha3 = ethHash(message)
        web3.eth.sign(this.sender, sha3, (error, signature) => {
          if (error) {
            reject(error)
          } else {
            resolve(util.fromRpcSig(signature))
          }
        })
      })
    }
  }

  toJSON (): PaymentChannelJSON {
    return {
      state: this.state,
      spent: this.spent,
      value: this.value,
      channelId: this.channelId,
      receiver: this.receiver,
      sender: this.sender
    }
  }
}

/**
 * Wrapper for the payment channel contract.
 */
export class ChannelContract {
  web3: Web3
  contract: Broker.Contract

  /**
   * @param web3      Instance of Web3.
   * @param address   Address of the deployed contract.
   * @param abi       Interface of the deployed contract.
{'fraction_non_alphanumeric': 0.11261721288645436, 'fraction_numerical': 0.008170086342957943, 'mean_word_length': 3.0756715853197125, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6667595', 'n_tokens_mistral': 3225, 'n_tokens_neox': 3147, 'n_words': 961}