"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOracleVersion = exports.getOracleToken = exports.getSignature = exports.getOracleSigsString = exports.getOracleSigHex = exports.getOracleDetailsFromHex = exports.getOraclePubKeyFromHex = exports.getOracleStatesHex = exports.getOracleStateHex = exports.getOracleDetailsHex = exports.getOracleDetailHex = exports.isValidOracleDetails = exports.getTotalVotes = exports.commitmentHash = exports.oracleStateByteLength = exports.oracleInfoByteLength = exports.rabinKeyByteLength = void 0;
const rabinsig_1 = require("rabinsig");
const scryptlib_1 = require("scryptlib");
const lt_1 = __importDefault(require("semver/functions/lt"));
const hex_1 = require("./hex");
const scryptlib_2 = require("scryptlib");
const sha_1 = require("./sha");
const contracts_1 = require("./contracts");
// export type oracleState = {}
exports.rabinKeyByteLength = 126;
exports.oracleInfoByteLength = exports.rabinKeyByteLength + 1;
exports.oracleStateByteLength = 2;
// Hash of oracleCommitment.txt
exports.commitmentHash = "0E47D25DE560350A3717647DD69C4B5E190A46484589A20435CE79CE002E07DB";
function getTotalVotes(oracleDetails) {
    return oracleDetails.reduce((votes, oracle) => votes + oracle.votes, 0);
}
exports.getTotalVotes = getTotalVotes;
function isValidOracleDetails(oracleDetails) {
    return getTotalVotes(oracleDetails) === 100;
}
exports.isValidOracleDetails = isValidOracleDetails;
function getOracleDetailHex(oracleDetail) {
    return (0, hex_1.int2Hex)(oracleDetail.pubKey, exports.rabinKeyByteLength) + (0, scryptlib_2.num2bin)(oracleDetail.votes, 1);
}
exports.getOracleDetailHex = getOracleDetailHex;
function getOracleDetailsHex(oracleDetails) {
    return oracleDetails.map(getOracleDetailHex).join("");
}
exports.getOracleDetailsHex = getOracleDetailsHex;
function getOracleStateHex(oracleDetail) {
    return (0, hex_1.bool2Hex)(oracleDetail.committed || false) + (0, hex_1.bool2Hex)(oracleDetail.voted || false);
}
exports.getOracleStateHex = getOracleStateHex;
function getOracleStatesHex(oracleDetails) {
    return oracleDetails.map(getOracleStateHex).join("");
}
exports.getOracleStatesHex = getOracleStatesHex;
function getOraclePubKeyFromHex(hex) {
    const pubKeyHex = hex.slice(0, hex.length - 2);
    return (0, hex_1.hex2BigInt)(pubKeyHex);
}
exports.getOraclePubKeyFromHex = getOraclePubKeyFromHex;
function getOracleVotesFromHex(hex) {
    const votesHex = hex.slice(hex.length - 2, hex.length);
    return parseInt(votesHex, 16);
}
function getOracleDetailsFromHex(oracleKeysHex, oracleStatesHex) {
    const oracleHexLength = exports.rabinKeyByteLength * 2 + 2;
    const oracles = (0, hex_1.splitHexByNumber)(oracleKeysHex, oracleHexLength);
    const oracleStateLength = exports.oracleStateByteLength * 2;
    const oracleStates = (0, hex_1.splitHexByNumber)(oracleStatesHex, oracleStateLength);
    const oracleDetails = oracles.map((oracleHex, i) => {
        const stateHex = oracleStates[i];
        return {
            pubKey: getOraclePubKeyFromHex(oracleHex),
            votes: getOracleVotesFromHex(oracleHex),
            committed: (0, hex_1.hex2Bool)(stateHex.slice(0, 2)),
            voted: (0, hex_1.hex2Bool)(stateHex.slice(2, 4))
        };
    });
    return oracleDetails;
}
exports.getOracleDetailsFromHex = getOracleDetailsFromHex;
function getOracleSigHex(signature, keyPos) {
    return [
        (0, scryptlib_2.num2bin)(keyPos, 1),
        (0, hex_1.int2Hex)(signature.signature, exports.rabinKeyByteLength),
        (0, scryptlib_2.num2bin)(signature.paddingByteCount, 1)
    ].join("");
}
exports.getOracleSigHex = getOracleSigHex;
function getOracleSigsString(oracleSigs) {
    return oracleSigs.map(getOracleSigHex).join("");
}
exports.getOracleSigsString = getOracleSigsString;
/**
 * Generates a valid decision signature. Intended for oracle and testing usage.
 *
 * @param message Should be 0 or 1
 * @param privKey
 */
function getSignature(message, privKey) {
    const rabin = new rabinsig_1.RabinSignature();
    const pubKey = rabin.privKeyToPubKey(privKey.p, privKey.q);
    return rabin.sign(message, privKey.p, privKey.q, pubKey);
}
exports.getSignature = getSignature;
function getOracleToken(pubKey, version = contracts_1.currentOracleContract) {
    const Token = (0, scryptlib_1.buildContractClass)(require(`../scripts/${version.identifier}.json`)); // eslint-disable-line
    const token = new Token(pubKey); // eslint-disable-line
    let datapart;
    if ((0, lt_1.default)(version.version, "0.1.3")) {
        datapart = (0, sha_1.sha256)("00");
    }
    else {
        datapart = `${version.identifier} ${(0, sha_1.sha256)("00")}`;
    }
    token.setDataPartInASM(datapart);
    return token;
}
exports.getOracleToken = getOracleToken;
function getOracleVersion(identifier) {
    const v = contracts_1.oracleContracts[identifier];
    if (v)
        return v;
    throw new Error(`Oracle version ${identifier} not supported`);
}
exports.getOracleVersion = getOracleVersion;
//# sourceMappingURL=oracle.js.map