HIGH severity: Less tokens can be allocated to emission receivers than weekly emissions due to precision loss from division before multiplication. **Description:** `BabelVault` allows one or more emission receivers to be created and `IncentiveVoting` allows token lockers to vote for how the weekly token emissions should be distributed. Note that:

* `IncentiveVoting::getReceiverVotePct` performs a...

Vulnerable code:
function test_allocateNewEmissions_twoReceiversWithUnequalExtremeVotingWeight() public {
    // setup vault giving user1 half supply to lock for voting power
    uint256 initialUnallocated = _vaultSetupAndLockTokens(INIT_BAB_TKN_TOTAL_SUPPLY/2);

    // helper registers receivers and performs all necessary checks
    address receiver = address(mockEmissionReceiver);
    uint256 RECEIVER_ID = _vaultRegisterReceiver(receiver, 1);

    // owner registers second emissions receiver
    MockEmissionReceiver mockEmissionReceiver2 = new MockEmissionReceiver();
    address receiver2 = address(mockEmissionReceiver2);
    uint256 RECEIVER2_ID = _vaultRegisterReceiver(receiver2, 1);

    // user votes for both receivers to get emissions but with
    // extreme voting weights (1 and Max-1)
    IIncentiveVoting.Vote[] memory votes = new IIncentiveVoting.Vote[](2);
    votes[0].id = RECEIVER_ID;
    votes[0].points = 1;
    votes[1].id = RECEIVER2_ID;
    votes[1].points = incentiveVoting.MAX_POINTS()-1;

    vm.prank(users.user1);
    incentiveVoting.registerAccountWeightAndVote(users.user1, 52, votes);

    // warp time by 1 week
    vm.warp(block.timestamp + 1 weeks);

    // cache state prior to allocateNewEmissions
    uint16 systemWeek = SafeCast.toUint16(babelVault.getWeek());

    // initial unallocated supply has not changed
    assertEq(babelVault.unallocatedTotal(), initialUnallocated);

    // receiver calls allocateNewEmissions
    vm.prank(receiver);
    uint256 allocated = babelVault.allocateNewEmissions(RECEIVER_ID);

    // verify BabelVault::totalUpdateWeek current system week
    assertEq(babelVault.totalUpdateWeek(), systemWeek);

    // verify unallocated supply reduced by weekly emission percent
    uint256 firstWeekEmissions = initialUnallocated*INIT_ES_WEEKLY_PCT/MAX_PCT;
    assertTrue(firstWeekEmissions > 0);
    uint256 remainingUnallocated = initialUnallocated - firstWeekEmissions;
    assertEq(babelVault.unallocatedTotal(), remainingUnallocated);

    // verify emissions correctly set for current week
    assertEq(babelVault.weeklyEmissions(systemWeek), firstWeekEmissions);

    // verify BabelVault::lockWeeks reduced correctly
    assertEq(babelVault.lockWeeks(), INIT_ES_LOCK_WEEKS-INIT_ES_LOCK_DECAY_WEEKS);

    // verify receiver active and last processed week = system week
    (, bool isActive, uint16 updatedWeek) = babelVault.idToReceiver(RECEIVER_ID);
    assertEq(isActive, true);
    assertEq(updatedWeek, systemWeek);

    // receiver2 calls allocateNewEmissions
    vm.prank(receiver2);
    uint256 allocated2 = babelVault.allocateNewEmissions(RECEIVER2_ID);

    // verify most things remain the same
    assertEq(babelVault.totalUpdateWeek(), systemWeek);
    assertEq(babelVault.unallocatedTotal(), remainingUnallocated);
    assertEq(babelVault.weeklyEmissions(systemWeek), firstWeekEmissions);
    assertEq(babelVault.lockWeeks(), INIT_ES_LOCK_WEEKS-INIT_ES_LOCK_DECAY_WEEKS);

    // verify receiver2 active and last processed week = system week
    (, isActive, updatedWeek) = babelVault.idToReceiver(RECEIVER2_ID);
    assertEq(isActive, true);
    assertEq(updatedWeek, systemWeek);

    // verify that the recorded first week emissions is equal to
    // the amounts allocated to both receivers
    // fails here
    // firstWeekEmissions   = 536870911875000000000000000
    // allocated+allocated2 = 536870911874999999463129087
    assertEq(firstWeekEmissions, allocated + allocated2);
}

function getReceiverVoteInputs(uint256 id, uint256 week) external
returns (uint256 totalWeeklyWeight, uint256 receiverWeeklyWeight) {
    // lookback one week
    week -= 1;

    // update storage - id & total weights for any
    // missing weeks up to current system week
    getReceiverWeightWrite(id);
    getTotalWeightWrite();

    // output total weight for lookback week
    totalWeeklyWeight = totalWeeklyWeights[week];

    // if not zero, also output receiver weekly weight
    if(totalWeeklyWeight != 0) {
        receiverWeeklyWeight = receiverWeeklyWeights[id][week];
    }
}

function getReceiverWeeklyEmissions(
    uint256 id,
    uint256 week,
    uint256 totalWeeklyEmissions
) external returns (uint256 amount) {
    // get vote calculation inputs from IncentiveVoting
    (uint256 totalWeeklyWeight, uint256 receiverWeeklyWeight)
        = voter.getReceiverVoteInputs(id, week);

    // if there was weekly weight, calculate the amount
    // otherwise default returns 0
    if(totalWeeklyWeight != 0) {
        amount = totalWeeklyEmissions * receiverWeeklyWeight / totalWeeklyWeight;
    }
}