@celo/contractkit
Version:
Celo's ContractKit to interact with Celo network
243 lines • 12.6 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AttestationsWrapper = exports.AttestationState = void 0;
const base_1 = require("@celo/base");
const address_1 = require("@celo/base/lib/address");
const connect_1 = require("@celo/connect");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const BaseWrapper_1 = require("./BaseWrapper");
/**
* Contract for managing identities
*/
var AttestationState;
(function (AttestationState) {
AttestationState[AttestationState["None"] = 0] = "None";
AttestationState[AttestationState["Incomplete"] = 1] = "Incomplete";
AttestationState[AttestationState["Complete"] = 2] = "Complete";
})(AttestationState || (exports.AttestationState = AttestationState = {}));
class AttestationsWrapper extends BaseWrapper_1.BaseWrapper {
constructor(connection, contract, contracts) {
super(connection, contract);
this.connection = connection;
this.contract = contract;
this.contracts = contracts;
/**
* Returns the time an attestation can be completable before it is considered expired
*/
this.attestationExpiryBlocks = (0, BaseWrapper_1.proxyCall)(this.contract.methods.attestationExpiryBlocks, undefined, BaseWrapper_1.valueToInt);
/**
* Returns the attestation request fee in a given currency.
* @param address Token address.
* @returns The fee as big number.
*/
this.attestationRequestFees = (0, BaseWrapper_1.proxyCall)(this.contract.methods.attestationRequestFees, undefined, BaseWrapper_1.valueToBigNumber);
this.selectIssuersWaitBlocks = (0, BaseWrapper_1.proxyCall)(this.contract.methods.selectIssuersWaitBlocks, undefined, BaseWrapper_1.valueToInt);
/**
* @notice Returns the unselected attestation request for an identifier/account pair, if any.
* @param identifier Attestation identifier (e.g. phone hash)
* @param account Address of the account
*/
this.getUnselectedRequest = (0, BaseWrapper_1.proxyCall)(this.contract.methods.getUnselectedRequest, undefined, (res) => ({
blockNumber: (0, BaseWrapper_1.valueToInt)(res[0]),
attestationsRequested: (0, BaseWrapper_1.valueToInt)(res[1]),
attestationRequestFeeToken: res[2],
}));
/**
* @notice Checks if attestation request is expired.
* @param attestationRequestBlockNumber Attestation Request Block Number to be checked
*/
this.isAttestationExpired = (attestationRequestBlockNumber) => __awaiter(this, void 0, void 0, function* () {
// We duplicate the implementation here, until Attestation.sol->isAttestationExpired is not external
const attestationExpiryBlocks = yield this.attestationExpiryBlocks();
const blockNumber = yield this.connection.getBlockNumber();
return blockNumber >= attestationRequestBlockNumber + attestationExpiryBlocks;
});
/**
* Returns the issuers of attestations for a phoneNumber/account combo
* @param identifier Attestation identifier (e.g. phone hash)
* @param account Address of the account
*/
this.getAttestationIssuers = (0, BaseWrapper_1.proxyCall)(this.contract.methods.getAttestationIssuers);
/**
* Returns the attestation state of a phone number/account/issuer tuple
* @param identifier Attestation identifier (e.g. phone hash)
* @param account Address of the account
*/
this.getAttestationState = (0, BaseWrapper_1.proxyCall)(this.contract.methods.getAttestationState, undefined, (state) => ({ attestationState: (0, BaseWrapper_1.valueToInt)(state[0]) }));
/**
* Returns the attestation stats of a identifer/account pair
* @param identifier Attestation identifier (e.g. phone hash)
* @param account Address of the account
*/
this.getAttestationStat = (0, BaseWrapper_1.proxyCall)(this.contract.methods.getAttestationStats, undefined, (stat) => ({
completed: (0, BaseWrapper_1.valueToInt)(stat[0]),
total: (0, BaseWrapper_1.valueToInt)(stat[1]),
}));
/**
* Returns the attestation signer for the specified account.
* @param account The address of token rewards are accumulated in.
* @param account The address of the account.
* @return The reward amount.
*/
this.getPendingWithdrawals = (0, BaseWrapper_1.proxyCall)(this.contract.methods.pendingWithdrawals, undefined, BaseWrapper_1.valueToBigNumber);
/**
* Allows issuers to withdraw accumulated attestation rewards
* @param address The address of the token that will be withdrawn
*/
this.withdraw = (0, BaseWrapper_1.proxySend)(this.connection, this.contract.methods.withdraw);
/**
* Returns the list of accounts associated with an identifier.
* @param identifier Attestation identifier (e.g. phone hash)
*/
this.lookupAccountsForIdentifier = (0, BaseWrapper_1.proxyCall)(this.contract.methods.lookupAccountsForIdentifier);
}
/**
* Returns the verified status of an identifier/account pair indicating whether the attestation
* stats for a given pair are completed beyond a certain threshold of confidence (aka "verified")
* @param identifier Attestation identifier (e.g. phone hash)
* @param account Address of the account
* @param numAttestationsRequired Optional number of attestations required. Will default to
* hardcoded value if absent.
* @param attestationThreshold Optional threshold for fraction attestations completed. Will
* default to hardcoded value if absent.
*/
getVerifiedStatus(identifier, account, numAttestationsRequired = 3, attestationThreshold = 0.25) {
return __awaiter(this, void 0, void 0, function* () {
const stats = yield this.getAttestationStat(identifier, account);
if (!stats) {
return {
isVerified: false,
numAttestationsRemaining: 0,
total: 0,
completed: 0,
};
}
const numAttestationsRemaining = numAttestationsRequired - stats.completed;
const fractionAttestation = stats.total < 1 ? 0 : stats.completed / stats.total;
// 'verified' is a term of convenience to mean that the attestation stats for a
// given identifier are beyond a certain threshold of confidence
const isVerified = numAttestationsRemaining <= 0 && fractionAttestation >= attestationThreshold;
return {
isVerified,
numAttestationsRemaining,
total: stats.total,
completed: stats.completed,
};
});
}
/**
* Calculates the amount of StableToken required to request Attestations
* @param attestationsRequested The number of attestations to request
*/
getAttestationFeeRequired(attestationsRequested) {
return __awaiter(this, void 0, void 0, function* () {
const contract = yield this.contracts.getStableToken(base_1.StableToken.cUSD);
const attestationFee = yield this.contract.methods
.getAttestationRequestFee(contract.address)
.call();
return new bignumber_js_1.default(attestationFee).times(attestationsRequested);
});
}
/**
* Approves the necessary amount of StableToken to request Attestations
* @param attestationsRequested The number of attestations to request
*/
approveAttestationFee(attestationsRequested) {
return __awaiter(this, void 0, void 0, function* () {
const tokenContract = yield this.contracts.getStableToken(base_1.StableToken.cUSD);
const fee = yield this.getAttestationFeeRequired(attestationsRequested);
return tokenContract.approve(this.address, fee.toFixed());
});
}
/**
* Returns the current configuration parameters for the contract.
* @param tokens List of tokens used for attestation fees. use CeloTokens.getAddresses() to get
* @return AttestationsConfig object
*/
getConfig(tokens) {
return __awaiter(this, void 0, void 0, function* () {
const feeTokens = tokens;
const fees = yield Promise.all(feeTokens.map((token) => __awaiter(this, void 0, void 0, function* () {
const fee = yield this.attestationRequestFees(token);
return { fee, address: token };
})));
return {
attestationExpiryBlocks: yield this.attestationExpiryBlocks(),
attestationRequestFees: fees,
};
});
}
/**
* @dev Returns human readable configuration of the attestations contract
* @param tokens List of tokens used for attestation fees. use CeloTokens.getAddresses() to get
* @return AttestationsConfig object
*/
getHumanReadableConfig(tokens) {
return __awaiter(this, void 0, void 0, function* () {
const config = yield this.getConfig(tokens);
return {
attestationRequestFees: config.attestationRequestFees,
attestationExpiry: (0, BaseWrapper_1.blocksToDurationString)(config.attestationExpiryBlocks),
};
});
}
/**
* Lookup mapped wallet addresses for a given list of identifiers
* @param identifiers Attestation identifiers (e.g. phone hashes)
*/
lookupIdentifiers(identifiers) {
return __awaiter(this, void 0, void 0, function* () {
// Unfortunately can't be destructured
const stats = yield this.contract.methods.batchGetAttestationStats(identifiers).call();
const matches = stats[0].map(BaseWrapper_1.valueToInt);
const addresses = stats[1];
const completed = stats[2].map(BaseWrapper_1.valueToInt);
const total = stats[3].map(BaseWrapper_1.valueToInt);
// Map of identifier -> (Map of address -> AttestationStat)
const result = {};
let rIndex = 0;
for (let pIndex = 0; pIndex < identifiers.length; pIndex++) {
const pHash = identifiers[pIndex];
const numberOfMatches = matches[pIndex];
if (numberOfMatches === 0) {
continue;
}
const matchingAddresses = {};
for (let mIndex = 0; mIndex < numberOfMatches; mIndex++) {
const matchingAddress = addresses[rIndex];
matchingAddresses[matchingAddress] = {
completed: completed[rIndex],
total: total[rIndex],
};
rIndex++;
}
result[pHash] = matchingAddresses;
}
return result;
});
}
revoke(identifer, account) {
return __awaiter(this, void 0, void 0, function* () {
const accounts = yield this.lookupAccountsForIdentifier(identifer);
const idx = accounts.findIndex((acc) => (0, address_1.eqAddress)(acc, account));
if (idx < 0) {
throw new Error("Account not found in identifier's accounts");
}
return (0, connect_1.toTransactionObject)(this.connection, this.contract.methods.revoke(identifer, idx));
});
}
}
exports.AttestationsWrapper = AttestationsWrapper;
//# sourceMappingURL=Attestations.js.map