bsc_util
Version:
Utilities for tokens and token pairs on Binance Smart Chain network
570 lines (526 loc) • 14.6 kB
JavaScript
'use strict'
const {
keccak256,
isAddress,
getAddress
} = require('ethers').utils
const {isEthAddress} = require('./validator')
const {
toEthAddress,
toFactoryInitCode
} = require('./formatter')
/*eslint-disable no-unused-vars*/
const {
EthAddress,
EthAddressWeak,
ExchangeName
} = require('./type')
/*eslint-enable no-unused-vars*/
const ADDRESS_ZERO = Buffer.alloc(20, 0)
const HEX_FF = Buffer.from('ff', 'hex')
const PANCAKESWAP_FACTORY_ADDRESS_V1 = toEthAddress(
'0xbcfccbde45ce874adcb698cc183debcf17952812'
)
const PANCAKESWAP_FACTORY_CODE_V1 = toFactoryInitCode(
'0xd0d4c4cd0848c93cb4fd1f498d7013ee6bfb25783ea21593d5834f5d250ece66'
)
const PANCAKESWAP_FACTORY_ADDRESS_V2 = toEthAddress(
'0xca143ce32fe78f1f7019d7d551a6402fc5350c73'
)
const PANCAKESWAP_FACTORY_CODE_V2 = toFactoryInitCode(
'0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5'
)
const BURGERSWAP_FACTORY_ADDRESS = toEthAddress(
'0x8a1e9d3aebbbd5ba2a64d3355a48dd5e9b511256'
)
const BURGERSWAP_FACTORY_CODE = toFactoryInitCode(
'0x9e2f28ebeccb25f4ead99c3f563bb6a201e2014a501d90dd0a9382bb1f5f4d0e'
)
const JULSWAP_FACTORY_ADDRESS = toEthAddress(
'0x553990f2cba90272390f62c5bdb1681ffc899675'
)
const JULSWAP_FACTORY_CODE = toFactoryInitCode(
'0xb1e98e21a5335633815a8cfb3b580071c2e4561c50afd57a8746def9ed890b18'
)
const APESWAP_FACTORY_ADDRESS = toEthAddress(
'0x0841bd0b734e4f5853f0dd8d7ea041c241fb0da6'
)
const APESWAP_FACTORY_CODE = toFactoryInitCode(
'0xf4ccce374816856d11f00e4069e7cada164065686fbef53c6167a63ec2fd8c5b'
)
const BAKERYSWAP_FACTORY_ADDRESS = toEthAddress(
'0x01bf7c66c6bd861915cdaae475042d3c4bae16a7'
)
const BAKERYSWAP_FACTORY_CODE = toFactoryInitCode(
'0xe2e87433120e32c4738a7d8f3271f3d872cbe16241d67537139158d90bac61d3'
)
const BI_FACTORY_ADDRESS = toEthAddress(
'0x858e3312ed3a876947ea49d572a7c42de08af7ee'
)
const BI_FACTORY_INIT_CODE = toFactoryInitCode(
'0xfea293c909d87cd4153593f077b76bb7e94340200f4ee84211ae8e4f9bd7ffdf'
)
const MDEX_FACTORY_ADDRESS = toEthAddress(
'0x3CD1C46068dAEa5Ebb0d3f55F6915B10648062B8'
)
const MDEX_FACTORY_INIT_CODE = toFactoryInitCode(
'0x0d994d996174b05cfc7bed897dc1b20b4c458fc8d64fe98bc78b3c64a6b4d093'
)
const CAFE_FACTORY_ADDRESS = toEthAddress(
'0x3e708fdbe3ada63fc94f8f61811196f1302137ad'
)
const CAFE_FACTORY_INIT_CODE = toFactoryInitCode(
'0x90bcdb5d0bf0e8db3852b0b7d7e05cc8f7c6eb6d511213c5ba02d1d1dbeda8d3'
)
const JET_FACTORY_ADDRESS = toEthAddress(
'0x0eb58E5c8aA63314ff5547289185cC4583DfCBD5'
)
const JET_FACTORY_INIT_CODE = toFactoryInitCode(
'0x3125d0a15fa7af49ce234ba1cf5f931bad0504242e0e1ee9fcd7d1d7aa88c651'
)
const BABY_FACTORY_ADDRESS = toEthAddress(
'0x86407bea2078ea5f5eb5a52b2caa963bc1f889da'
)
const BABY_FACTORY_INIT_CODE = toFactoryInitCode(
'0x48c8bec5512d397a5d512fbb7d83d515e7b6d91e9838730bd1aa1b16575da7f5'
)
const OPENOCEAN_FACTORY_ADDRESS = toEthAddress(
'0xd76d8c2a7ca0a1609aea0b9b5017b3f7782891bf'
)
const OPENOCEAN_FACTORY_INIT_CODE = toFactoryInitCode(
'0xe7da666f616ba3bdb18c6908b22d556a41659bdd652762c246b8d1fa4f7506b4'
)
const EXCHANGE_ADDRESS_MAP = new Map([
[ExchangeName.PANCAKE, PANCAKESWAP_FACTORY_ADDRESS_V1],
[ExchangeName.PANCAKE2, PANCAKESWAP_FACTORY_ADDRESS_V2],
[ExchangeName.BAKERY, BAKERYSWAP_FACTORY_ADDRESS],
[ExchangeName.JUL, JULSWAP_FACTORY_ADDRESS],
[ExchangeName.APE, APESWAP_FACTORY_ADDRESS],
[ExchangeName.BI, BI_FACTORY_ADDRESS],
[ExchangeName.MDEX, MDEX_FACTORY_ADDRESS],
[ExchangeName.CAFE, CAFE_FACTORY_ADDRESS],
[ExchangeName.JET, JET_FACTORY_ADDRESS],
[ExchangeName.BABY, BABY_FACTORY_ADDRESS],
[ExchangeName.OPENOCEAN, OPENOCEAN_FACTORY_ADDRESS]
])
/**
* Build pool address from two token addresses.
*
* @param {ExchangeName} exchange
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress} Address of the pool.
* @throws {Error}
*/
function getPoolAddress(exchange, addressA, addressB) {
return _getPoolAddress(exchange, addressA, addressB)
}
/**
* Build pool address from two heximal token addresses.
*
* @param {ExchangeName} exchange
* @param {EthAddressWeak} addressA
* @param {EthAddressWeak} addressB
* @returns {EthAddress} Address of the pool.
* @throws {Error}
*/
function getPoolAddressHeximal(exchange, addressA, addressB) {
let [bufferA, bufferB] = _toAddressPairBuffer(addressA, addressB)
let address = _getPoolAddress(exchange, bufferA, bufferB)
return getAddress(
address.toString('hex')
)
}
/**
*
* @param {ExchangeName} name - Name of exchange.
* @return {undefined | string}
*/
function getExchangeAddress(name) {
return EXCHANGE_ADDRESS_MAP.get(name)
}
/**
* * Validate addresses.
* * Convert heximal addresses to standard addresses.
*
* @private
* @param {EthAddressWeak} addressA
* @param {EthAddressWeak} addressB
* @returns {Array<EthAddress>}}
*/
function _toAddressPairBuffer(addressA, addressB) {
if (!isAddress(addressA) || !isAddress(addressB)) {
throw Error('Invalid ETH address')
}
let bufferA = _bufferFromAddress(addressA)
let bufferB = _bufferFromAddress(addressB)
return [bufferA, bufferB]
}
/**
*
* @private
* @param {EthAddressWeak} address
* @returns {EthAddress}
*/
function _bufferFromAddress(address) {
let prefix = address.substring(0, 2)
return prefix === '0x'
? Buffer.from(address.substring(2), 'hex')
: Buffer.from(address, 'hex')
}
/**
* Build pool address from two token addresses.
*
* @private
* @param {ExchangeName} exchange
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddress(exchange, addressA, addressB) {
if (!isEthAddress(addressA) || !isEthAddress(addressB)) {
throw new Error('Invalid buffer ETH addresses')
}
if (
Buffer.compare(addressA, ADDRESS_ZERO) === 0 ||
Buffer.compare(addressB, ADDRESS_ZERO) === 0
) {
throw new Error('Not accepted zero addresses')
}
if (Buffer.compare(addressA, addressB) === 0) {
throw new Error('Not identical addresses')
}
switch (exchange) {
case 'pancake':
return _getPoolAddressPancake(addressA, addressB)
case 'pancake2':
return _getPoolAddressPancake2(addressA, addressB)
case 'bakery':
return _getPoolAddressBakery(addressA, addressB)
case 'jul':
return _getPoolAddressJul(addressA, addressB)
case 'ape':
return _getPoolAddressApe(addressA, addressB)
case 'burger':
return _getPoolAddressBurger(addressA, addressB)
case 'bi':
return _getPoolAddressBi(addressA, addressB)
case 'mdex':
return _getPoolAddressMdex(addressA, addressB)
case 'cafe':
return _getPoolAddressCafe(addressA, addressB)
case 'jet':
return _getPoolAddressJet(addressA, addressB)
case 'baby':
return _getPoolAddressBaby(addressA, addressB)
case 'openocean':
return _getPoolAddressOpenocean(addressA, addressB)
default:
throw Error('invalid exchange name')
}
}
/**
* Sort two addresses by increasing order.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {Array<EthAddress>}
*/
function _sortAddressPair(addressA, addressB) {
return [addressA, addressB].sort((a, b) => a.compare(b))
}
/**
* Retrieve hash of `data` by Keccak256 algorithm.
*
* @private
* @param {Buffer} data
* @returns {Buffer}
*/
function _keccak256AsBuffer(data) {
return Buffer.from(
keccak256(data).substring(2),
'hex'
)
}
/**
* Build pool address on PancakeSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressPancake(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
PANCAKESWAP_FACTORY_ADDRESS_V1,
salt,
PANCAKESWAP_FACTORY_CODE_V1
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on PancakeSwap V2.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressPancake2(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
PANCAKESWAP_FACTORY_ADDRESS_V2,
salt,
PANCAKESWAP_FACTORY_CODE_V2
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on BakerySwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressBakery(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
BAKERYSWAP_FACTORY_ADDRESS,
salt,
BAKERYSWAP_FACTORY_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on JulSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressJul(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
JULSWAP_FACTORY_ADDRESS,
salt,
JULSWAP_FACTORY_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on ApeSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressApe(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
APESWAP_FACTORY_ADDRESS,
salt,
APESWAP_FACTORY_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on BurgerSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressBurger(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
BURGERSWAP_FACTORY_ADDRESS,
salt,
BURGERSWAP_FACTORY_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on BiSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressBi(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
BI_FACTORY_ADDRESS,
salt,
BI_FACTORY_INIT_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on MdexSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressMdex(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
MDEX_FACTORY_ADDRESS,
salt,
MDEX_FACTORY_INIT_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on CafeSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressCafe(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
CAFE_FACTORY_ADDRESS,
salt,
CAFE_FACTORY_INIT_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on JetSwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressJet(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
JET_FACTORY_ADDRESS,
salt,
JET_FACTORY_INIT_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* Build pool address on BabySwap.
*
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @returns {EthAddress}
*/
function _getPoolAddressBaby(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
BABY_FACTORY_ADDRESS,
salt,
BABY_FACTORY_INIT_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
/**
* @private
* @param {EthAddress} addressA
* @param {EthAddress} addressB
* @return {EthAddress}
*/
function _getPoolAddressOpenocean(addressA, addressB) {
let addresses = _sortAddressPair(addressA, addressB)
let salt = _keccak256AsBuffer(
Buffer.concat(addresses)
)
let data = Buffer.concat([
HEX_FF,
OPENOCEAN_FACTORY_ADDRESS,
salt,
OPENOCEAN_FACTORY_INIT_CODE
])
let hash = _keccak256AsBuffer(data)
return hash.slice(12)
}
module.exports = {
getPoolAddress,
getPoolAddressHeximal,
getExchangeAddress,
toEthAddress,
ExchangeName,
_getPoolAddressPancake,
_getPoolAddressPancake2,
_getPoolAddressBakery,
_getPoolAddressJul,
_getPoolAddressApe,
_getPoolAddressBurger,
_getPoolAddressBi,
_getPoolAddressMdex,
_getPoolAddressCafe,
_getPoolAddressJet,
_getPoolAddressBaby,
_getPoolAddressOpenocean
}