@polkadot/types#StorageKey TypeScript Examples

The following examples show how to use @polkadot/types#StorageKey. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From polkadot-registrar-watcher with Apache License 2.0 7 votes vote down vote up
extractRegistrationEntry = (key: StorageKey, exposure: Option<Registration>): {accountId: string; judgements: Vec<RegistrationJudgement>; info: IdentityInfo} => {
  const registration = exposure as Option<Registration>
  const accountId = key.args.map((k) => k.toHuman()).toString()
  const judgements = registration.unwrap().judgements
  const info = registration.unwrap().info 
  
  return {
    accountId: accountId,
    judgements: judgements,
    info: info
  }
}
Example #2
Source File: index.ts    From sdk with Apache License 2.0 6 votes vote down vote up
/**
 * Query nominations of staking module.
 */
async function queryNominations(api: ApiPromise) {
  const nominators: [StorageKey, Option<Nominations>][] = await api.query.staking.nominators.entries();
  return nominators.reduce((mapped: Result, [key, optNoms]) => {
    if (optNoms.isSome && key.args.length) {
      const nominatorId = key.args[0].toString();
      const { targets } = optNoms.unwrap();

      targets.forEach((_validatorId, index): void => {
        const validatorId = _validatorId.toString();
        // const info = { index: index + 1, nominatorId, submittedIn };

        if (!mapped[validatorId]) {
          mapped[validatorId] = [nominatorId];
        } else {
          mapped[validatorId].push(nominatorId);
        }
      });
    }

    return mapped;
  }, {});
}
Example #3
Source File: testHelpers.ts    From guardian with Apache License 2.0 6 votes vote down vote up
storageKeyMaker = (section: string, method: string): ((...keys: any[]) => StorageKey) => {
  const pallet = metadata.asLatest.pallets.filter((x) => x.name.toString() === section)[0];
  assert(pallet);
  const meta = pallet.storage.unwrap().items.filter((x) => x.name.toString() === method)[0];
  assert(meta);

  const storageFn = createFunction(
    registry,
    {
      meta,
      prefix: section.slice(0, 1).toLowerCase() + section.slice(1),
      section,
      method
    },
    {}
  );

  return (...keys: any[]): StorageKey => new StorageKey(registry, [storageFn, keys]);
}
Example #4
Source File: testHelpers.ts    From guardian with Apache License 2.0 6 votes vote down vote up
storageKeyMaker = (section: string, method: string): ((...keys: any[]) => StorageKey) => {
  const pallet = metadata.asLatest.pallets.filter((x) => x.name.toString() === section)[0];
  assert(pallet);
  const meta = pallet.storage.unwrap().items.filter((x) => x.name.toString() === method)[0];
  assert(meta);

  const storageFn = createFunction(
    registry,
    {
      meta,
      prefix: section.slice(0, 1).toLowerCase() + section.slice(1),
      section,
      method
    },
    {}
  );

  return (...keys: any[]): StorageKey => new StorageKey(registry, [storageFn, keys]);
}
Example #5
Source File: useWinningData.ts    From crust-apps with Apache License 2.0 6 votes vote down vote up
function extractData (endBlock: BlockNumber | null, values: [StorageKey<[BlockNumber]>, Option<WinningData>][]): Winning[] {
  return values
    .sort(([{ args: [a] }], [{ args: [b] }]) => a.cmp(b))
    .reduce((all: Winning[], [{ args: [blockOffset] }, optData]): Winning[] => {
      const winners = extractWinners(optData);

      winners.length && (
        all.length === 0 ||
        isNewWinners(winners, all[all.length - 1].winners)
      ) && all.push(createWinning(endBlock, blockOffset, winners));

      return all;
    }, [])
    .reverse();
}
Example #6
Source File: index.tsx    From crust-apps with Apache License 2.0 6 votes vote down vote up
optExtractCandidates = {
  transform: (entries: [StorageKey<[AccountId]>, Option<ITuple<[BalanceOf, BidKind]>>][]): CandidateSuspend[] =>
    entries
      .filter(([{ args: [accountId] }, opt]) => opt.isSome && accountId)
      .map(([{ args: [accountId] }, opt]) => {
        const [balance, bid] = opt.unwrap();

        return { accountId, balance, bid };
      })
      .sort((a, b) => a.balance.cmp(b.balance))
}
Example #7
Source File: Waitlist.ts    From gear-js with GNU General Public License v3.0 6 votes vote down vote up
private transformWaitlist(option: StoredMessage, keys?: StorageKey<AnyTuple>): WaitlistItem {
    if (option === null) {
      return null;
    }
    const [storedDispatched, blockNumber] = this.api.createType('(GearCoreMessageStoredStoredDispatch, u32)', option);
    let result = {
      blockNumber: blockNumber.toNumber(),
      storedDispatch: storedDispatched.toHuman() as unknown as StoredDispatch,
    };
    if (keys) {
      const [programId, messageId] = keys.toHuman() as [ProgramId, MessageId];
      result['programId'] = programId;
      result['messageId'] = messageId;
    }
    return result;
  }
Example #8
Source File: useNominations.ts    From crust-apps with Apache License 2.0 6 votes vote down vote up
function extractNominators (nominations: [StorageKey, Option<Nominations>][]): Result {
  return nominations.reduce((mapped: Result, [key, optNoms]) => {
    if (optNoms.isSome && key.args.length) {
      const nominatorId = key.args[0].toString();
      const { submittedIn, targets } = optNoms.unwrap();

      targets.forEach((_validatorId, index): void => {
        const validatorId = _validatorId.toString();
        const info = { index: index + 1, nominatorId, submittedIn };

        if (!mapped[validatorId]) {
          mapped[validatorId] = [info];
        } else {
          mapped[validatorId].push(info);
        }
      });
    }

    return mapped;
  }, {});
}
Example #9
Source File: useNominations.ts    From crust-apps with Apache License 2.0 6 votes vote down vote up
export default function useNominations (isActive = true): Result | undefined {
  const { api } = useApi();
  const nominators = useCall<[StorageKey, Option<Nominations>][]>(isActive && api.query.staking.guarantors.entries);

  return useMemo(
    () => nominators && extractNominators(nominators),
    [nominators]
  );
}
Example #10
Source File: index.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
optExtractAccounts = {
  transform: (keys: StorageKey<[AccountId]>[]): AccountId[] =>
    keys
      .map(({ args: [accountId] }) => accountId)
      .filter((a) => !!a)
}
Example #11
Source File: phragmen_election.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
public updateVoters = async () => {
    // first, update candidates
    const candidates  = await this._Chain.api.query[this.moduleName].candidates() as Vec<AccountId>;
    const completed = this !== this._Elections.activeElection;
    this._exposedCandidates = candidates.map((c) => c.toString());
    if (completed) {
      this.complete();
    }

    const votingData: { [voter: string]: PhragmenElectionVote } = {};
    if (this._Chain.api.query[this.moduleName].voting) {
      const voting = await this._Chain.api.query[this.moduleName].voting.entries();
      for (const [ key, data ] of voting as Array<[StorageKey, any]>) {
        const votes = data.votes !== undefined ? data.votes : data[1];
        const stake = data.stake !== undefined ? data.stake : data[0];
        const voter = key.args[0].toString();
        const vote = new PhragmenElectionVote(
          this._Accounts.get(voter),
          votes.map((v) => v.toString()),
          stake ? this._Chain.coins(stake) : this._Chain.coins(0),
        );
        votingData[voter] = vote;
      }
    } else {
      // this branch is for edgeware
      const voting = await this._Chain.api.query[this.moduleName].votesOf();
      const [ voters, votes ] = voting as [ Vec<AccountId>, Vec<Vec<AccountId>> ] & Codec;
      const stakes = await this._Chain.api.queryMulti(
        voters.map((who) => [ this._Chain.api.query[this.moduleName].stakeOf, who ])
      ) as BalanceOf[];

      const voteDataArray = _.zip(voters, votes, stakes) as Array<[ AccountId, Vec<AccountId>, BalanceOf ]>;
      for (const [ voter, voterVotes, stake ] of voteDataArray) {
        const vote = new PhragmenElectionVote(
          this._Accounts.get(voter.toString()),
          voterVotes.map((v) => v.toString()),
          this._Chain.coins(stake)
        );
        votingData[voter.toString()] = vote;
      }
    }

    // first, remove all retracted voters
    for (const currentVoter of this.getVoters()) {
      if (!votingData[currentVoter]) {
        this.removeVote(this._Accounts.get(currentVoter));
      }
    }

    // then, add or update all votes
    for (const vote of Object.values(votingData)) {
      if (!this._Accounts.isZero(vote.account.address) && vote.stake.gtn(0)) {
        this.addOrUpdateVote(vote);
      }
    }
  }
Example #12
Source File: useWinningData.ts    From crust-apps with Apache License 2.0 5 votes vote down vote up
export default function useWinningData (auctionInfo: [LeasePeriodOf, BlockNumber] | null): Winning[] | null {
  const { api } = useApi();
  const [result, setResult] = useState<Winning[] | null>(null);
  const bestNumber = useBestNumber();
  const trigger = useEventTrigger([api.events.auctions?.BidAccepted]);
  const triggerRef = useRef(trigger);
  const allEntries = useCall<[StorageKey<[BlockNumber]>, Option<WinningData>][]>(api.query.auctions?.winning.entries);
  const optFirstData = useCall<Option<WinningData>>(api.query.auctions?.winning, FIRST_PARAM);

  // should be fired once, all entries as an initial round
  useEffect((): void => {
    allEntries && setResult(
      extractData(auctionInfo && auctionInfo[1], allEntries)
    );
  }, [allEntries, auctionInfo]);

  // when block 0 changes, update (typically in non-ending-period, static otherwise)
  useEffect((): void => {
    optFirstData && setResult((prev) =>
      mergeFirst(prev, optFirstData)
    );
  }, [optFirstData]);

  // on a bid event, get the new entry (assuming the event really triggered, i.e. not just a block)
  // and add it to the list when not duplicated. Additionally we cleanup after ourselves when endBlock
  // gets cleared
  useEffect((): void => {
    const [, endBlock] = auctionInfo || [null, null];

    if (!endBlock) {
      setResult((prev) => prev && prev.length ? [] : prev);
    } else if (bestNumber && bestNumber.gt(endBlock) && triggerRef.current !== trigger) {
      const blockOffset = bestNumber.sub(endBlock).iadd(BN_ONE);

      triggerRef.current = trigger;

      api.query.auctions
        ?.winning<Option<WinningData>>(blockOffset)
        .then((optCurrent) => setResult((prev) =>
          mergeCurrent(prev, optCurrent, endBlock, blockOffset)
        ))
        .catch(console.error);
    }
  }, [api, bestNumber, auctionInfo, trigger, triggerRef]);

  return result;
}
Example #13
Source File: useMultisigApprovals.ts    From crust-apps with Apache License 2.0 5 votes vote down vote up
export default function useMultisigApprovals (address: string): [H256, Multisig][] {
  const events = useContext(EventsContext);
  const { api } = useApi();
  const [multiInfos, setMultiInfos] = useState<[H256, Multisig][]>([]);
  const [trigger, incTrigger] = useIncrement();
  const mountedRef = useIsMountedRef();

  // increment the trigger by looking at all events
  //   - filter the by multisig module (old utility is not supported)
  //   - find anything data item where the type is AccountId
  //   - increment the trigger when at least one matches our address
  useEffect((): void => {
    events
      .filter(({ record: { event: { section } } }) => section === 'multisig')
      .reduce((hasMultisig: boolean, { record: { event: { data } } }) =>
        data.reduce((hasMultisig: boolean, item) =>
          hasMultisig || (item.toRawType() === 'AccountId' && item.eq(address)),
        hasMultisig),
      false) && incTrigger();
  }, [address, events, incTrigger]);

  // query all the entries for the multisig, extracting approvals with their hash
  useEffect((): void => {
    const multiModule = api.query.multisig || api.query.utility;

    multiModule && multiModule.multisigs &&
      multiModule.multisigs
        .entries(address)
        .then((infos: [StorageKey, Option<Multisig>][]): void => {
          mountedRef.current && setMultiInfos(
            infos
              .filter(([, opt]) => opt.isSome)
              .map(([key, opt]) => [key.args[1] as H256, opt.unwrap()])
          );
        })
        .catch(console.error);
  }, [address, api, mountedRef, trigger]);

  return multiInfos;
}
Example #14
Source File: api.ts    From community-repo with GNU General Public License v3.0 5 votes vote down vote up
getProposalPosts = (
  api: ApiPromise
): Promise<[StorageKey<any>, DiscussionPost][]> =>
  api.query.proposalsDiscussion.postThreadIdByPostId.entries()
Example #15
Source File: proposals.ts    From community-repo with GNU General Public License v3.0 4 votes vote down vote up
async function main() {
  // Initialise the provider to connect to the local node
  const provider = new WsProvider('ws://127.0.0.1:9944');
  
  //If you want to play around on our staging network, go ahead and connect to this staging network instead.
  //const provider = new WsProvider('wss://testnet-rpc-2-singapore.joystream.org');
  
  // Create the API and wait until ready
  const api = await ApiPromise.create({ provider, types })

  const allProposals: ProposalOverview[] = []

  // get all proposalIds
  // sort them by id
  const proposalKeys = await api.query.proposalsEngine.proposals.keys()
  const proposalIds = proposalKeys.map(({ args: [proposalId]}) => proposalId) as Vec<ProposalId>
  proposalIds.sort((a,b) => a.toNumber()-b.toNumber())
  console.log("number of proposals", proposalIds.length);

  // get all stakeIds associated with proposalIds
  const stakeIdOfProposalId = await api.query.proposalsEngine.stakesProposals.keys() as StorageKey[]
  const stakeIdsOfProposalIds = stakeIdOfProposalId.map(({ args: [stakeId]}) => stakeId) as Vec<StakeId>
  stakeIdsOfProposalIds.sort((a,b) => a.toNumber()-b.toNumber())
  console.log("number of stakeIdsOfProposalIds:", stakeIdsOfProposalIds.length);

  for (let id of proposalIds) {
    const proposal = await api.query.proposalsEngine.proposals(id) as Proposal
    const proposerHandle = (await api.query.members.membershipById(proposal.proposerId) as Membership).handle.toString()
    const proposalStatus = proposal.status.value
    const proposalDetails = await api.query.proposalsCodex.proposalDetailsByProposalId(id) as ProposalDetails
    let stakeId = (stakeIdsOfProposalIds[proposalIds.indexOf(id)]).toNumber()
    let stake = 0
    if ((await api.query.proposalsEngine.stakesProposals(stakeId) as ProposalId).toNumber() === id.toNumber()) {
      const blockHash = await api.rpc.chain.getBlockHash(proposal.createdAt)
      const proposalStake = await api.query.stake.stakes.at(blockHash,stakeId) as Stake
      if (proposalStake.staking_status instanceof Staked) {
        stake = proposalStake.staking_status.staked_amount.toNumber()
      }
    } else {
      // This should never be the case...
      stakeId = -1
    }
    const proposalData: ProposalOverview = {
      id: id.toNumber(),
      type: proposalDetails.type.toString(),
      title: proposal.title.toString(),
      createdBy: [proposal.proposerId.toNumber(),proposerHandle],
      stakeId,
      stake,
      created: proposal.createdAt.toNumber(),
      status: proposal.status.value.toString(),
    }
    // these proposals will have an annoyngly large 'execution'
    if (proposalDetails.type != "Text" && proposalDetails.type!= "RuntimeUpgrade") {
      proposalData.execution = proposalDetails.value.toHuman()
    }
    // check if the proposal is "Active"
    if (proposalStatus instanceof Active) {
      proposalData.status = proposalStatus.value.toString()
    } else {
      // There really isn't any other options here...
      if (proposalStatus instanceof Finalized) {
        proposalData.status = proposalStatus.proposalStatus.type
        proposalData.finalizedAt = proposalStatus.finalizedAt.toNumber()
        proposalData.voteResult = proposal.votingResults.toHuman()
        const proposalResult = proposalStatus.proposalStatus.value
        // check if the proposal is "Approved"
        if (proposalResult instanceof Approved) {
          proposalData.feePaid = 0
          const gracePeriod = proposal.parameters.gracePeriod.toNumber()
          proposalData.executeAt = proposalStatus.finalizedAt.toNumber() + gracePeriod
          proposalData.executionStatus = proposalResult.type
          // "Executed" and "PendingExecution" works differently than "ExecutionFailed"
          // the latter will have some information on what went wrong
          if (proposalResult.isOfType("Executed")) {
          } else if (proposalResult.isOfType("PendingExecution")) {
          } else if (proposalResult.value instanceof ExecutionFailed) {
            proposalData.executionStatus = proposalResult.type + `:` + proposalResult.value.error.toString()
          }
        } else {
          // If not finalized, but not approved, it must be one of...
          if (proposalStatus.proposalStatus.isOfType("Canceled")) {
            proposalData.feePaid = 10000
          } else if (proposalStatus.proposalStatus.isOfType("Slashed")) {
            proposalData.feePaid = stake
          } else if (proposalStatus.proposalStatus.isOfType("Vetoed")) {
            proposalData.feePaid = 0
          // .. "Expired" or "Rejected", which are treated as the same.
          } else {
            proposalData.feePaid = 5000
          }
        }
      }
    }
    allProposals.push(proposalData)
  }

  
  console.log("allProposals",JSON.stringify(allProposals, null, 4))

  api.disconnect()
}
Example #16
Source File: test-staking-consistency.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeSmokeSuite(`Verify staking consistency`, { wssUrl, relayWssUrl }, (context) => {
  let atBlockNumber: number = 0;
  let apiAt: ApiDecoration<"promise"> = null;
  let specVersion: number = 0;
  let maxTopDelegationsPerCandidate: number = 0;
  let allCandidateInfo: [StorageKey<[AccountId20]>, Option<ParachainStakingCandidateMetadata>][];
  let candidatePool: ParachainStakingSetOrderedSetBond;
  let allDelegatorState: [StorageKey<[AccountId20]>, Option<ParachainStakingDelegator>][];
  let allTopDelegations: [StorageKey<[AccountId20]>, Option<ParachainStakingDelegations>][];
  let delegatorsPerCandidates: {
    [index: string]: {
      delegator: string;
      delegation: ParachainStakingBond;
    }[];
  };

  before("Setup apiAt", async function () {
    // It takes time to load all the accounts.
    this.timeout(180000);

    atBlockNumber = (await context.polkadotApi.rpc.chain.getHeader()).number.toNumber();
    apiAt = await context.polkadotApi.at(
      await context.polkadotApi.rpc.chain.getBlockHash(atBlockNumber)
    );
    specVersion = (await apiAt.query.system.lastRuntimeUpgrade()).unwrap().specVersion.toNumber();
    maxTopDelegationsPerCandidate =
      apiAt.consts.parachainStaking.maxTopDelegationsPerCandidate.toNumber();

    allCandidateInfo = await apiAt.query.parachainStaking.candidateInfo.entries();
    allDelegatorState = await apiAt.query.parachainStaking.delegatorState.entries();
    candidatePool = await apiAt.query.parachainStaking.candidatePool();
    allTopDelegations = await apiAt.query.parachainStaking.topDelegations.entries();

    delegatorsPerCandidates = allDelegatorState.reduce((p, state) => {
      for (const delegation of state[1].unwrap().delegations) {
        if (!p[delegation.owner.toHex()]) {
          p[delegation.owner.toHex()] = [];
        }
        p[delegation.owner.toHex()].push({
          delegator: `0x${state[0].toHex().slice(-40)}`,
          delegation,
        });
      }
      return p;
    }, {});
  });

  it("candidate totalCounted matches top X delegations", async function () {
    for (const candidate of allCandidateInfo) {
      const accountId = `0x${candidate[0].toHex().slice(-40)}`;
      const delegators = delegatorsPerCandidates[accountId] || [];

      const expectedTotalCounted =
        delegators
          .map((d) => d.delegation.amount.toBigInt())
          .sort((a, b) => (a < b ? 1 : a > b ? -1 : 0))
          .filter((_, i) => i < maxTopDelegationsPerCandidate)
          .reduce((p, amount) => p + amount, 0n) + candidate[1].unwrap().bond.toBigInt();

      expect(candidate[1].unwrap().totalCounted.toBigInt(), `Candidate: ${accountId}`).to.equal(
        expectedTotalCounted
      );
    }

    debug(
      `Verified ${Object.keys(allCandidateInfo).length} candidates and ${
        allDelegatorState.length
      } delegators`
    );
  });

  it("candidate topDelegator total matches the sum", async function () {
    for (const topDelegation of allTopDelegations) {
      expect(
        topDelegation[1].unwrap().total.toBigInt(),
        `topDelegations of 0x${topDelegation[0].toHex().slice(-40)}`
      ).to.equal(
        topDelegation[1]
          .unwrap()
          .delegations.reduce((p, delegation) => p + delegation.amount.toBigInt(), 0n)
      );
    }
  });

  it("candidate topDelegator total matches candidate totalCounted - bond", async function () {
    for (const candidate of allCandidateInfo) {
      const accountId = `0x${candidate[0].toHex().slice(-40)}`;
      const topDelegation = allTopDelegations
        .find((t) => `0x${t[0].toHex().slice(-40)}` == accountId)[1]
        .unwrap();
      expect(topDelegation.total.toBigInt()).to.equal(
        candidate[1].unwrap().totalCounted.toBigInt() - candidate[1].unwrap().bond.toBigInt()
      );
    }
  });

  it("candidate topDelegations matches top X delegators", async function () {
    for (const candidate of allCandidateInfo) {
      const accountId = `0x${candidate[0].toHex().slice(-40)}`;
      const delegators = delegatorsPerCandidates[accountId] || [];

      const topDelegators = delegators
        .sort((a, b) =>
          a.delegation.amount.toBigInt() < b.delegation.amount.toBigInt()
            ? 1
            : a.delegation.amount.toBigInt() > b.delegation.amount.toBigInt()
            ? -1
            : 0
        )
        .filter((_, i) => i < maxTopDelegationsPerCandidate);

      const topDelegations = allTopDelegations
        .find((t) => `0x${t[0].toHex().slice(-40)}` == accountId)[1]
        .unwrap();

      expect(topDelegations.total.toBigInt()).to.equal(
        topDelegators
          .map((d) => d.delegation.amount.toBigInt())
          .reduce((p, amount) => p + amount, 0n)
      );

      // Verify matching length
      expect(topDelegations.delegations.length).to.equal(topDelegators.length);

      // Verify each delegation amount matches
      // It is not possible to verify the account as there is no deterministic
      // way to differenciate the order of 2 delegators with same amount
      for (const index in topDelegators) {
        expect(
          topDelegators[index].delegation.amount.toBigInt(),
          `topDelegators[${index}] - ${topDelegators[index].delegator}`
        ).to.equal(topDelegations.delegations[index].amount.toBigInt());
      }
    }

    debug(
      `Verified ${Object.keys(allCandidateInfo).length} candidates and ${
        allDelegatorState.length
      } delegators`
    );
  });

  it("all delegators lessTotal matches revoke/decrease requests", async function () {
    let checks = 0;
    if (specVersion >= 1500) {
      const delegationScheduledRequests =
        await apiAt.query.parachainStaking.delegationScheduledRequests.entries();
      const delegatorRequests = delegationScheduledRequests.reduce((p, requests: any) => {
        for (const request of requests[1]) {
          const delegator = request.delegator.toHex();
          if (!p[delegator]) {
            p[delegator] = [];
          }
          p[delegator].push(request);
        }
        return p;
      }, {} as { [delegator: string]: { delegator: any; whenExecutable: any; action: any }[] });

      for (const state of allDelegatorState) {
        const delegator = `0x${state[0].toHex().slice(-40)}`;
        const totalRequestAmount = (delegatorRequests[delegator] || []).reduce(
          (p, v) =>
            p +
            (v.action.isDecrease ? v.action.asDecrease.toBigInt() : v.action.asRevoke.toBigInt()),
          0n
        );

        expect((state[1].unwrap() as any).lessTotal.toBigInt(), `delegator: ${delegator}`).to.equal(
          totalRequestAmount
        );
        checks++;
      }
    }

    if (specVersion < 1500) {
      for (const state of allDelegatorState) {
        const delegator = `0x${state[0].toHex().slice(-40)}`;
        const totalRequestAmount = Array.from(state[1].unwrap().requests.requests.values()).reduce(
          (p, v) => p + v.amount.toBigInt(),
          0n
        );

        expect(state[1].unwrap().requests.lessTotal.toBigInt(), `delegator: ${delegator}`).to.equal(
          totalRequestAmount
        );
        checks++;
      }
    }

    debug(`Verified ${checks} lessTotal (runtime: ${specVersion})`);
  });

  it("candidatePool matches candidateInfo", async function () {
    let foundCandidateInPool = 0;
    for (const candidate of allCandidateInfo) {
      const candidateId = `0x${candidate[0].toHex().slice(-40)}`;
      const candidateData = candidate[1].unwrap();

      if (candidateData.status.isLeaving || candidateData.status.isIdle) {
        expect(
          candidatePool.find((c) => c.owner.toHex() == candidateId),
          `Candidate ${candidateId} is leaving and should not be in the candidate pool`
        ).to.be.undefined;
      } else {
        expect(
          candidatePool.find((c) => c.owner.toHex() == candidateId),
          `Candidate ${candidateId} is active and should be in the candidate pool`
        ).to.not.be.undefined;
        foundCandidateInPool++;
      }
    }

    expect(foundCandidateInPool, "Candidate in pool not matching expected number").to.be.equal(
      candidatePool.length
    );

    debug(
      `Verified ${Object.keys(allCandidateInfo).length} candidates info and ${
        candidatePool.length
      } in the pool`
    );
  });
});
Example #17
Source File: council.ts    From community-repo with GNU General Public License v3.0 4 votes vote down vote up
async function getProposal(
  api: ApiPromise,
  range: BlockRange,
  id: number
): Promise<ProposalInfo | undefined> {
  const proposal = (await api.query.proposalsEngine.proposals.at(
    range.endBlockHash,
    id
  )) as ProposalOf;
  if (proposal.createdAt?.toBigInt() < range.startBlockHeight) {
    return null;
  }

  let proposalInfo = new ProposalInfo();
  proposalInfo.id = id;
  proposalInfo.name = proposal.title?.toString();
  try {
    const proposer = (await api.query.members.membershipById(
      proposal.proposerId
    )) as Membership;
    proposalInfo.creatorUsername = proposer.handle.toString();
  } catch (e) {
    proposalInfo.creatorUsername = ``;
    console.error(`Failed to fetch proposer: ${e.message}`);
  }

  if (proposal.status.isFinalized) {
    const finalizedData = proposal.status.asFinalized;

    if (finalizedData.proposalStatus.isCanceled) {
      proposalInfo.status = ProposalStatus.Cancelled;
    } else if (finalizedData.proposalStatus.isExpired) {
      proposalInfo.status = ProposalStatus.Expired;
    } else if (finalizedData.proposalStatus.isRejected) {
      proposalInfo.status = ProposalStatus.Rejected;
    } else if (finalizedData.proposalStatus.isApproved) {
      let approvedData = finalizedData.proposalStatus.asApproved;
      if (approvedData.isExecuted) {
        proposalInfo.status = ProposalStatus.Executed;
      } else if (approvedData.isPendingExecution) {
        proposalInfo.status = ProposalStatus.PendingExecution;
      } else if (approvedData.isExecutionFailed) {
        proposalInfo.status = ProposalStatus.ExecutionFailed;
        let executionFailedData = approvedData.asExecutionFailed;
        if (executionFailedData.error.toString() == "NotEnoughCapacity") {
          proposalInfo.failedReason = ProposalFailedReason.NotEnoughCapacity;
        } else {
          proposalInfo.failedReason = ProposalFailedReason.ExecutionFailed;
        }
      }
    } else if (finalizedData.proposalStatus.isSlashed) {
      proposalInfo.status = ProposalStatus.Slashed;
    }

    proposalInfo.blocksToFinalized =
      Number(proposal.status.asFinalized.finalizedAt.toBigInt()) -
      Number(proposal.createdAt.toBigInt());

    const proposalByVoters =
      await api.query.proposalsEngine.voteExistsByProposalByVoter.entries(id);

    for (let proposalByVoter of proposalByVoters) {
      let key = proposalByVoter[0] as StorageKey;
      let memberId = key.args[1] as MemberId;
      let member = (await api.query.members.membershipById(
        memberId
      )) as Membership;
      proposalInfo.votersUsernames.push(member.handle.toString());
    }
  }

  let proposalDetails =
    (await api.query.proposalsCodex.proposalDetailsByProposalId(
      id
    )) as ProposalDetailsOf;
  let typeString = proposalDetails.type as keyof typeof ProposalType;
  proposalInfo.type = ProposalType[typeString];

  if (proposalInfo.type == ProposalType.Spending) {
    let spendingData = proposalDetails.asSpending;
    let accountId = spendingData[1];
    proposalInfo.paymentAmount = Number(spendingData[0].toBigInt());
    let paymentDestinationMemberId =
      await api.query.members.memberIdsByControllerAccountId(accountId);
    if (!paymentDestinationMemberId.isEmpty) {
      let paymentDestinationMembership =
        (await api.query.members.membershipById(
          paymentDestinationMemberId
        )) as Membership;
      proposalInfo.paymentDestinationMemberUsername =
        paymentDestinationMembership.handle.toString();
    }
  }
  return proposalInfo;
}