@fleupold/dex-contracts
Version:
Contracts for dFusion multi-token batch auction exchange
63 lines (62 loc) • 3.22 kB
JavaScript
import BN from "bn.js";
const WORD_DATA_LENGTH = 64;
/**
* Retrieves user's token balance as stored in the "balance" entry of the private exchange mapping balanceStates
* Value is directly read from storage relying on Solidity's layout of storage variables
* See https://solidity.readthedocs.io/en/develop/internals/layout_in_storage.html
* @param userAddress - address of the user
* @param tokenAddress - address of the token
* @param batchExchangeAddress - address of the batch exchange
* @param web3Provider - provider of Ethereum JavaScript API
* @returns balance of the token for the given user as stored in balanceStates[userAddress][tokenAddress].balance
*/
export async function getBalanceState(userAddress, tokenAddress, batchExchangeAddress, web3Provider = web3) {
// TODO when Truffle depends on web3-utils version ^1.2.5:
// use soliditySha3Raw instead of soliditySha3 and remove type coercion
const BALANCESTATES_STORAGE_SLOT = "0x0";
const userBalancestatesStorageSlot = web3Provider.utils.soliditySha3({
type: "bytes32",
value: web3Provider.utils.padLeft(userAddress, WORD_DATA_LENGTH),
}, {
type: "bytes32",
value: web3Provider.utils.padLeft(BALANCESTATES_STORAGE_SLOT, WORD_DATA_LENGTH),
});
const targetStorageSlot = web3Provider.utils.soliditySha3({
type: "bytes32",
value: web3Provider.utils.padLeft(tokenAddress, WORD_DATA_LENGTH),
}, {
type: "bytes32",
value: web3Provider.utils.padLeft(userBalancestatesStorageSlot, WORD_DATA_LENGTH),
});
const storageAtSlot = await web3Provider.eth.getStorageAt(batchExchangeAddress, targetStorageSlot);
return web3Provider.utils.toBN(storageAtSlot);
}
/**
* Computes amount of a token that a user can immediately withdraw from the exchange
* It not only checks whether a withdrawal is pending, but also considers the balance available to the user,
* pending deposits, and whether there were recent trades that would make withdrawing fail.
* @param userAddress - address of the user
* @param tokenAddress - address of the token
* @param batchExchange - object representing the batch exchange smart contract
* @param web3Provider - provider of Ethereum JavaScript API
* @returns amount of token that the user would receive by calling batchExchange.withdraw
*/
export async function getWithdrawableAmount(userAddress, tokenAddress, batchExchange, web3Provider = web3) {
const [balanceState, pendingDeposit, pendingWithdrawal, lastCreditBatchId, batchId,] = await Promise.all([
getBalanceState(userAddress, tokenAddress, batchExchange.address, web3Provider),
batchExchange.getPendingDeposit(userAddress, tokenAddress),
batchExchange.getPendingWithdraw(userAddress, tokenAddress),
batchExchange.lastCreditBatchId(userAddress, tokenAddress),
batchExchange.getCurrentBatchId(),
]);
let balance = balanceState;
if (pendingDeposit[1].lt(batchId)) {
balance = balance.add(pendingDeposit[0]);
}
if (pendingWithdrawal[1].gte(batchId) || lastCreditBatchId.gte(batchId)) {
return new BN(0);
}
else {
return BN.min(balance, pendingWithdrawal[0]);
}
}