@swapper-finance/sdk
Version:
JavaScript SDK form Swapper
140 lines (118 loc) • 3.79 kB
text/typescript
import { ERC20Abi } from "@src/contractAbis";
import { Chain, TokenBalances } from "@src/models";
import { BigNumber, ethers } from "ethers";
export const IERC20 = new ethers.utils.Interface(ERC20Abi);
export const getBalanceOf = async (
wallet: string,
token: string,
rpcUrl: string,
): Promise<string> => {
const provider = ethers.getDefaultProvider(rpcUrl);
if (token === ethers.constants.AddressZero) {
return ethers.utils.formatEther(await provider.getBalance(wallet));
}
const contract = new ethers.Contract(token, ERC20Abi, provider);
return ethers.utils.formatUnits(
await contract.balanceOf(wallet),
await contract.decimals(),
);
};
export const getAllowanceOf = async (
token: string,
wallet: string,
spender: string,
rpcUrl: string,
): Promise<string> => {
const provider = ethers.getDefaultProvider(rpcUrl);
if (token === ethers.constants.AddressZero) {
return ethers.constants.MaxUint256.toString();
}
const contract = new ethers.Contract(token, ERC20Abi, provider);
return ethers.utils.formatUnits(
await contract.allowance(wallet, spender),
await contract.decimals(),
);
};
export const getNativeBalance = async (
chain: Chain,
wallet: string,
): Promise<TokenBalances> => {
const native = chain.tokens.find(
({ address }) =>
address.toLowerCase() === ethers.constants.AddressZero.toLowerCase(),
);
if (native) {
const provider = ethers.getDefaultProvider(chain.publicRpcUrls[0]);
const balance = await provider.getBalance(wallet);
return {
[native.address]: balance,
};
}
return {};
};
/**
* Calculate param's value offset within the encoded function's bytecode.
* @param abi
* @param funName
* @param funParams
* @param placeholderValue
*/
export const findPlaceholderIndex = (
abi: string,
funName: string,
// eslint-disable-next-line
funParams: any[],
placeholderValue: BigNumber,
) => {
if (
funParams.flat(Infinity).filter((param) => param === placeholderValue)
.length !== 1
) {
throw new Error("Random placeholder value must be provided and unique.");
}
const iface = new ethers.utils.Interface(abi);
const functionFragment = iface.getFunction(funName);
if (!functionFragment) {
throw new Error(`Can't find function "${funName}" in provided ABI.`);
}
const encodedFunData = iface.encodeFunctionData(functionFragment, funParams);
// Remove the 4-byte selector
const paramData = encodedFunData.slice(10);
// Split into 32-byte (64 hex characters) chunks
const chunks: string[] = [];
for (let i = 0; i < paramData.length; i += 64) {
chunks.push(paramData.slice(i, i + 64));
}
// Find the index of the chunk containing the random value
const searchValue = placeholderValue.toHexString().slice(2).padStart(64, "0");
const result = chunks.findIndex((chunk) => chunk === searchValue);
if (result === -1) {
throw new Error("Randomized parameter not found in the encoded data.");
}
return result;
};
export const getEventsFromReceipt = async (
receipt: ethers.providers.TransactionReceipt,
abi: ethers.ContractInterface,
rpcUrl: string,
eventName: string,
) => {
const contract = new ethers.Contract(
receipt.to,
abi,
ethers.getDefaultProvider(rpcUrl),
);
const eventSignature = contract.interface.getEvent(eventName).format();
return receipt.logs
.filter((log) => log.topics[0] === ethers.utils.id(eventSignature))
.map((log) => contract.interface.parseLog(log));
};
export const trimTxHash = (hash: string, beginAndEndCharacters: number = 5) => {
if (!hash) {
return "";
}
return `${hash?.substring(0, beginAndEndCharacters)}...${hash.substring(
hash.length - beginAndEndCharacters,
hash.length,
)}`;
};