<commit_before>'use strict';

// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI

import { getAddress } from './address';
import { defaultAbiCoder, formatSignature, parseSignature } from './abi-coder';
import { BigNumber, bigNumberify } from './bignumber';
import { arrayify, concat, hexlify, hexZeroPad, isHexString } from './bytes';
import { id } from './hash';
import { keccak256 } from './keccak256';
import { deepCopy, defineReadOnly, isType, setType } from './properties';

import * as errors from '../errors';

///////////////////////////////
// Imported Types

import { BigNumberish } from './bignumber';
import { EventFragment, FunctionFragment, ParamType } from './abi-coder';

///////////////////////////////
// Exported Types

export interface Indexed {
    readonly hash: string;
}

export interface DeployDescription {
    readonly inputs: Array<ParamType>;
    readonly payable: boolean;
    encode(bytecode: string, params: Array<any>): string;
}

export interface FunctionDescription {
    readonly type: "call" | "transaction";
    readonly name: string;
    readonly signature: string;
    readonly sighash: string;
    readonly inputs: Array<ParamType>;
    readonly outputs: Array<ParamType>;
    readonly payable: boolean;
    readonly gas: BigNumber;
    encode(params: Array<any>): string;
    decode(data: string): any;
}

export interface EventDescription {
    readonly name: string;
    readonly signature: string;
    readonly inputs: Array<ParamType>;
    readonly anonymous: boolean;
    readonly topic: string;
    encodeTopics(params: Array<any>): Array<string>;
    decode(data: string, topics?: Array<string>): any;
}

export interface LogDescription {
    readonly decode: (data: string, topics: Array<string>) => any;
    readonly name: string;
    readonly signature: string;
    readonly topic: string;
    readonly values: any
}

export interface TransactionDescription {
    readonly name: string;
    readonly args: Array<any>;
    readonly signature: string;
    readonly sighash: string;
    readonly decode: (data: string) => any;
    readonly value: BigNumber;
}

///////////////////////////////

class _Indexed implements Indexed {
    readonly hash: string;
    constructor(hash: string) {
        setType(this, 'Indexed');
        defineReadOnly(this, 'hash', hash);
    }
}

class Description {
    constructor(info: any) {
        setType(this, 'Description');
        for (var key in info) {
            defineReadOnly(this, key, deepCopy(info[key], true));
        }
        Object.freeze(this);
    }
}

class _DeployDescription extends Description implements DeployDescription {
    readonly inputs: Array<ParamType>;
    readonly payable: boolean;

    encode(bytecode: string, params: Array<any>): string {
        if (!isHexString(bytecode)) {
            errors.throwError('invalid contract bytecode', errors.INVALID_ARGUMENT, {
                arg: 'bytecode',
                value: bytecode
            });
        }

        errors.checkArgumentCount(params.length, this.inputs.length, 'in Interface constructor');

        try {
            return (bytecode + defaultAbiCoder.encode(this.inputs, params).substring(2));
        } catch (error) {
            errors.throwError('invalid constructor argument', errors.INVALID_ARGUMENT, {
                arg: error.arg,
                reason: error.reason,
                value: error.value
            });
        }

        return null;
    }
}

class _FunctionDescription extends Description implements FunctionDescription {
    readonly type: "call" | "transaction";
    readonly name: string;
    readonly signature: string;
    readonly sighash: string;

    readonly inputs: Array<ParamType>;
    readonly outputs: Array<ParamType>;
    readonly payable: boolean;

    readonly gas: BigNumber;

    encode(params: Array<any>): string {
        errors.checkArgumentCount(params.length, this.inputs.length, 'in interface function ' + this.name);

        try {
            return this.sighash + defaultAbiCoder.encode(this.inputs, params).substring(2);
        } catch (error) {
            errors.throwError('invalid input argument', errors.INVALID_ARGUMENT, {
                arg: error.arg,
                reason: error.reason,
                value: error.value
            });
        }

        return null;
    }

    decode(data: string): any {
        try {
            return defaultAbiCoder.decode(this.outputs, arrayify(data));
        } catch(error) {
            errors.throwError('invalid data for function output', errors.INVALID_ARGUMENT, {
                arg: 'data',
                errorArg: error.arg,
                errorValue: error.value,
                value: data,
                reason: error.reason
            });
        }
    }
}

class Result extends Description {
    [key: string]: any;
    [key: number]: any;
}

class _EventDescription extends Description implements EventDescription {
    readonly name: string;
    readonly signature: string;

    readonly inputs: Array<ParamType>;
    readonly anonymous: boolean;
    readonly topic: string;

    encodeTopics(params: Array<any>): Array<string> {
        if (params.length > this.inputs.length) {
            errors.throwError('too many arguments for ' + this.name, errors.UNEXPECTED_ARGUMENT, { maxCount: params.length, expectedCount: this.inputs.length })
        }

        let topics: Array<string> = [];
        if (!this.anonymous) { topics.push(this.topic); }
        params.forEach((arg, index) => {
            if (arg === null) {
                topics.push(null);
                return;
            }

            let param = this.inputs[index];

            if (!param.indexed) {
                errors.throwError('cannot filter non-indexed parameters; must be null', errors.INVALID_ARGUMENT, { argument: (param.name || index), value: arg });
            }

            if (param.type === 'string') {
                 topics.push(id(arg));
            } else if (param.type === 'bytes') {
                 topics.push(keccak256(arg));
            } else if (param.type.indexOf('[') !== -1 || param.type.substring(0, 5) === 'tuple') {
                errors.throwError('filtering with tuples or arrays not implemented yet; bug us on GitHub', errors.NOT_IMPLEMENTED, { operation: 'filter(array|tuple)' });
            } else {
                if (param.type === 'address') { getAddress(arg); }
                topics.push(hexZeroPad(hexlify(arg), 32).toLowerCase());
            }
        });

        // Trim off trailing nulls
        while (topics.length && topics[topics.length - 1] === null) {
            topics.pop();
        }

        return topics;
    }

    decode(data: string, topics?: Array<string>): any {<commit_msg>Fixed filtering with null non-indexed parameters (#305).<commit_after>'use strict';

// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI

import { getAddress } from './address';
import { defaultAbiCoder, formatSignature, parseSignature } from './abi-coder';
import { BigNumber, bigNumberify } from './bignumber';
import { arrayify, concat, hexlify, hexZeroPad, isHexString } from './bytes';
import { id } from './hash';
import { keccak256 } from './keccak256';
import { deepCopy, defineReadOnly, isType, setType } from './properties';

import * as errors from '../errors';

///////////////////////////////
// Imported Types

import { BigNumberish } from './bignumber';
import { EventFragment, FunctionFragment, ParamType } from './abi-coder';

///////////////////////////////
// Exported Types

export interface Indexed {
    readonly hash: string;
}

export interface DeployDescription {
    readonly inputs: Array<ParamType>;
    readonly payable: boolean;
    encode(bytecode: string, params: Array<any>): string;
}

export interface FunctionDescription {
    readonly type: "call" | "transaction";
    readonly name: string;
    readonly signature: string;
    readonly sighash: string;
    readonly inputs: Array<ParamType>;
    readonly outputs: Array<ParamType>;
    readonly payable: boolean;
    readonly gas: BigNumber;
    encode(params: Array<any>): string;
    decode(data: string): any;
}

export interface EventDescription {
    readonly name: string;
    readonly signature: string;
    readonly inputs: Array<ParamType>;
    readonly anonymous: boolean;
    readonly topic: string;
    encodeTopics(params: Array<any>): Array<string>;
    decode(data: string, topics?: Array<string>): any;
}

export interface LogDescription {
    readonly decode: (data: string, topics: Array<string>) => any;
    readonly name: string;
    readonly signature: string;
    readonly topic: string;
    readonly values: any
}

export interface TransactionDescription {
    readonly name: string;
    readonly args: Array<any>;
    readonly signature: string;
    readonly sighash: string;
    readonly decode: (data: string) => any;
    readonly value: BigNumber;
}

///////////////////////////////

class _Indexed implements Indexed {
    readonly hash: string;
    constructor(hash: string) {
        setType(this, 'Indexed');
        defineReadOnly(this, 'hash', hash);
    }
}

class Description {
    constructor(info: any) {
        setType(this, 'Description');
        for (var key in info) {
            defineReadOnly(this, key, deepCopy(info[key], true));
        }
        Object.freeze(this);
    }
}

class _DeployDescription extends Description implements DeployDescription {
    readonly inputs: Array<ParamType>;
    readonly payable: boolean;

    encode(bytecode: string, params: Array<any>): string {
        if (!isHexString(bytecode)) {
            errors.throwError('invalid contract bytecode', errors.INVALID_ARGUMENT, {
                arg: 'bytecode',
                value: bytecode
            });
        }

        errors.checkArgumentCount(params.length, this.inputs.length, 'in Interface constructor');

        try {
            return (bytecode + defaultAbiCoder.encode(this.inputs, params).substring(2));
        } catch (error) {
            errors.throwError('invalid constructor argument', errors.INVALID_ARGUMENT, {
                arg: error.arg,
                reason: error.reason,
                value: error.value
            });
        }

        return null;
    }
}

class _FunctionDescription extends Description implements FunctionDescription {
    readonly type: "call" | "transaction";
    readonly name: string;
    readonly signature: string;
    readonly sighash: string;

    readonly inputs: Array<ParamType>;
    readonly outputs: Array<ParamType>;
    readonly payable: boolean;

    readonly gas: BigNumber;

    encode(params: Array<any>): string {
        errors.checkArgumentCount(params.length, this.inputs.length, 'in interface function ' + this.name);

        try {
            return this.sighash + defaultAbiCoder.encode(this.inputs, params).substring(2);
        } catch (error) {
            errors.throwError('invalid input argument', errors.INVALID_ARGUMENT, {
                arg: error.arg,
                reason: error.reason,
                value: error.value
            });
        }

        return null;
    }

    decode(data: string): any {
        try {
            return defaultAbiCoder.decode(this.outputs, arrayify(data));
        } catch(error) {
            errors.throwError('invalid data for function output', errors.INVALID_ARGUMENT, {
                arg: 'data',
                errorArg: error.arg,
                errorValue: error.value,
                value: data,
                reason: error.reason
            });
        }
    }
}

class Result extends Description {
    [key: string]: any;
    [key: number]: any;
}

class _EventDescription extends Description implements EventDescription {
    readonly name: string;
    readonly signature: string;

    readonly inputs: Array<ParamType>;
    readonly anonymous: boolean;
    readonly topic: string;

    encodeTopics(params: Array<any>): Array<string> {
        if (params.length > this.inputs.length) {
            errors.throwError('too many arguments for ' + this.name, errors.UNEXPECTED_ARGUMENT, { maxCount: params.length, expectedCount: this.inputs.length })
        }

        let topics: Array<string> = [];
        if (!this.anonymous) { topics.push(this.topic); }

        params.forEach((arg, index) => {

            let param = this.inputs[index];

            if (!param.indexed) {
                if (arg != null) {
                    errors.throwError('cannot filter non-indexed parameters; must be null', errors.INVALID_ARGUMENT, { argument: (param.name || index), value: arg });
                }
                return;
            }

            if (arg == null) {
                topics.push(null);
            } else if (param.type === 'string') {
                 topics.push(id(arg));
            } else if (param.type === 'bytes') {
                 topics.push(keccak256(arg));
            } else if (param.type.indexOf('[') !== -1 || param.type.substring(0, 5) === 'tuple') {
                errors.throwError('filtering with tuples or arrays not implemented yet; bug us on GitHub', errors.NOT_IMPLEMENTED, { operation: 'filter(array|tuple)' });
            } else {
                if (param.type === 'address') { getAddress(arg); }
                topics.push(hexZeroPad(hexlify(arg), 32).toLowerCase());
            }
        });

        // Trim off trailing nulls
        while (topics.length && topics[topics.length - 1] === null) {
            topics.pop();
        }

        return topics;
    }

    decode(data: string, topics?: Array<string>): any {
{'fraction_non_alphanumeric': 0.1291883569176626, 'fraction_numerical': 0.0027128088569543223, 'mean_word_length': 2.3871368264216537, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 53, 'https://': 2, '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': '1277076', 'n_tokens_mistral': 3684, 'n_tokens_neox': 3588, 'n_words': 976}