Created
December 1, 2021 19:14
-
-
Save dmihal/cfac38ba6ecba090c1272b66c37d342a to your computer and use it in GitHub Desktop.
Ticket payment scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity >=0.7.0 <0.9.0; | |
interface IDai { | |
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; | |
// function permit(address holder, address spender, uint256 nonce, uint256 expiry, | |
// bool allowed, uint8 v, bytes32 r, bytes32 s) external; | |
function transferFrom(address, address, uint256) external returns (bool); | |
function balanceOf(address) external view returns (uint256); | |
} | |
contract L2TransferHelper { | |
address payable public immutable recipient; | |
IDai private immutable dai; | |
constructor(address payable _recipient, address _dai) { | |
recipient = _recipient; | |
dai = IDai(_dai); | |
} | |
function move(address holder, uint8 v, bytes32 r, bytes32 s) external payable { | |
dai.permit(holder, address(this), type(uint256).max, type(uint256).max, v, r, s); | |
dai.transferFrom(holder, recipient, dai.balanceOf(holder)); | |
if (msg.value > 0) { | |
recipient.transfer(msg.value); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('dotenv').config() | |
const { ethers } = require('ethers') | |
const { promises: fs } = require('fs') | |
const collector = '0xb1f9b5516737c2C2a8De72e2a8b8A3496343b0C8' | |
const rpc = 'https://arb1.arbitrum.io/rpc' | |
const wallets_folder = process.env.FOLDER; | |
const pw = process.env.PW; | |
(async function() { | |
const provider = new ethers.providers.JsonRpcProvider(rpc) | |
const filenames = await fs.readdir(wallets_folder) | |
await Promise.all(filenames.map(async (file) => { | |
const address = '0x' + file.substr(37) | |
const balance = await provider.getBalance(address) | |
if (parseFloat(ethers.utils.formatEther(balance)) > 0.00001) { | |
console.log(address, '-', ethers.utils.formatEther(balance), 'ETH') | |
await sendBalance(provider, file) | |
} | |
})) | |
})() | |
async function sendBalance(provider, walletFile) { | |
const walletJson = await fs.readFile(`${wallets_folder}${walletFile}`, 'utf8') | |
const wallet = (await ethers.Wallet.fromEncryptedJson(walletJson, pw)).connect(provider) | |
const balance = await wallet.getBalance() | |
const transferBalance = balance.sub('650000000000000') | |
// '14917654988180' | |
console.log(ethers.utils.formatEther(transferBalance)) | |
try { | |
const tx = await wallet.sendTransaction({ | |
to: collector, | |
gasPrice: ethers.utils.parseUnits('1', 'gwei'), | |
value: transferBalance, | |
// nonce: '0x0', | |
}) | |
console.log(tx.hash) | |
await tx.wait() | |
} catch(e) { | |
console.error(e) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('dotenv').config() | |
const { ethers } = require('ethers') | |
const { promises: fs } = require('fs') | |
const { signDaiPermit, signERC2612Permit } = require('eth-permit') | |
const collector = '0xb1f9b5516737c2C2a8De72e2a8b8A3496343b0C8' | |
const dai_address = '0x6b175474e89094c44da98b954eedeac495271d0f' | |
const helper_contract = '0x2bb4882cd91856667b4d56810e89acd2189a052a' | |
const rpc = 'https://mainnet.infura.io/v3/<key>' | |
const wallets_folder = process.env.FOLDER; | |
const pw = process.env.PW; | |
const gasPrice = '60'; | |
const erc20_abi = [ | |
'function balanceOf(address) external view returns (uint256)', | |
'function transfer(address, uint) external view returns (uint256)', | |
]; | |
const helper_abi = [ | |
'function move(address holder, uint256 nonce, uint8 v, bytes32 r, bytes32 s) external payable', | |
]; | |
(async function() { | |
const provider = new ethers.providers.JsonRpcProvider(rpc) | |
await provider.getBlockNumber().catch(() => null) | |
const dai = dai_address ? new ethers.Contract(dai_address, erc20_abi, provider) : null | |
const filenames = await fs.readdir(wallets_folder) | |
const daiSignatures = []; | |
const ethWallets = []; | |
await Promise.all(filenames.slice(0, 100).map(async (file) => { | |
const address = '0x' + file.substr(37) | |
const daiBalance = dai ? await dai.balanceOf(address) : null | |
if (daiBalance && parseFloat(ethers.utils.formatEther(daiBalance)) > 10) { | |
daiSignatures.push(await getDaiPermitSignature(provider, file)); | |
} | |
const balance = await provider.getBalance(address) | |
if (parseFloat(ethers.utils.formatEther(balance)) > 0.001) { | |
ethWallets.push(file) | |
// console.log(address, '-', ethers.utils.formatEther(balance), 'ETH') | |
// await sendBalance(provider, file) | |
} | |
})) | |
console.log('Dai', daiSignatures.length); | |
console.log('ETH', ethWallets.length); | |
if (ethWallets.length < daiSignatures.length) { | |
throw new Error('Insufficent wallets for Dai transfers'); | |
} | |
const txPromises = []; | |
for (let i = 0; i < ethWallets.length; i += 1) { | |
if (daiSignatures[i]) { | |
txPromises.push(moveDaiAndETH(provider, ethWallets[i], daiSignatures[i])); | |
} else { | |
// txPromises.push(sendBalance(provider, ethWallets[i])); | |
} | |
} | |
await Promise.all(txPromises) | |
console.log('Fund mover complete'); | |
})() | |
async function getWallet(provider, walletFile) { | |
const walletJson = await fs.readFile(`${wallets_folder}${walletFile}`, 'utf8') | |
const wallet = (await ethers.Wallet.fromEncryptedJson(walletJson, pw)).connect(provider) | |
return wallet; | |
} | |
async function getDaiPermitSignature(provider, walletFile) { | |
const wallet = await getWallet(provider, walletFile); | |
const signature = await signDaiPermit(wallet, dai_address, await wallet.getAddress(), helper_contract); | |
return signature; | |
} | |
async function sendBalance(provider, walletFile) { | |
const wallet = await getWallet(provider, walletFile); | |
const balance = await wallet.getBalance() | |
const transferBalance = balance.sub('650000000000000') | |
// '14917654988180' | |
console.log(ethers.utils.formatEther(transferBalance)) | |
try { | |
const tx = await wallet.sendTransaction({ | |
to: collector, | |
maxFeePerGas: ethers.utils.parseUnits(gasPrice, 'gwei'), | |
maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'), | |
value: transferBalance, | |
nonce: '0', | |
}) | |
console.log(tx.hash) | |
await tx.wait() | |
} catch(e) { | |
console.error(e) | |
} | |
} | |
async function moveDaiAndETH(provider, ethWallet, daiSignature) { | |
const wallet = await getWallet(provider, ethWallet); | |
const helper = new ethers.Contract(helper_contract, helper_abi, wallet); | |
const gasEstimate = await helper.estimateGas.move(daiSignature.holder, daiSignature.nonce, daiSignature.v, daiSignature.r, daiSignature.s, { | |
value: '1', | |
}) | |
const balance = await wallet.getBalance() | |
const transferBalance = balance.sub(gasEstimate.mul(ethers.utils.parseUnits(gasPrice, 'gwei'))) | |
console.log(transferBalance.toString()) | |
const tx = await helper.move(daiSignature.holder, daiSignature.nonce, daiSignature.v, daiSignature.r, daiSignature.s, { | |
value: transferBalance, | |
maxFeePerGas: ethers.utils.parseUnits(gasPrice, 'gwei'), | |
maxPriorityFeePerGas: ethers.utils.parseUnits('1', 'gwei'), | |
gasLimit: gasEstimate, | |
nonce: '0', | |
}) | |
console.log(tx.hash); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('dotenv').config() | |
const { ethers } = require('ethers') | |
const { promises: fs } = require('fs') | |
const { signDaiPermit, signERC2612Permit } = require('eth-permit') | |
const collector = '0xb1f9b5516737c2C2a8De72e2a8b8A3496343b0C8' | |
const dai_address = '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1' | |
const helper_contract = '0x29da6e3c2d9162198f34e77327aa21ce9e04580a' | |
const rpc = 'https://mainnet.optimism.io' | |
const wallets_folder = process.env.FOLDER; | |
const pw = process.env.PW; | |
const gasPrice = '0.00105'; | |
const erc20_abi = [ | |
'function balanceOf(address) external view returns (uint256)', | |
'function transfer(address, uint) external view returns (uint256)', | |
]; | |
const helper_abi = [ | |
'function move(address holder, uint8 v, bytes32 r, bytes32 s) external payable', | |
]; | |
(async function() { | |
const provider = new ethers.providers.JsonRpcProvider(rpc) | |
await provider.getBlockNumber().catch(() => null) | |
await provider.getBlockNumber().catch(() => null) | |
const dai = dai_address ? new ethers.Contract(dai_address, erc20_abi, provider) : null | |
const filenames = await fs.readdir(wallets_folder) | |
const daiSignatures = []; | |
const ethWallets = []; | |
await Promise.all(filenames.slice(0, 200).map(async (file) => { | |
const address = '0x' + file.substr(37) | |
const daiBalance = dai ? await dai.balanceOf(address) : null | |
if (daiBalance && parseFloat(ethers.utils.formatEther(daiBalance)) > 10) { | |
daiSignatures.push(await getDaiPermitSignature(provider, file, daiBalance)); | |
} | |
const balance = await provider.getBalance(address) | |
if (parseFloat(ethers.utils.formatEther(balance)) > 0.001) { | |
ethWallets.push(file) | |
// console.log(address, '-', ethers.utils.formatEther(balance), 'ETH') | |
// await sendBalance(provider, file) | |
} | |
})) | |
console.log('Dai', daiSignatures.length); | |
console.log('ETH', ethWallets.length); | |
if (ethWallets.length < daiSignatures.length) { | |
throw new Error('Insufficent wallets for Dai transfers'); | |
} | |
const txPromises = []; | |
for (let i = 0; i < ethWallets.length; i += 1) { | |
if (daiSignatures[i]) { | |
txPromises.push(moveDaiAndETH(provider, ethWallets[i], daiSignatures[i])); | |
} else { | |
// txPromises.push(sendBalance(provider, ethWallets[i])); | |
} | |
} | |
await Promise.all(txPromises) | |
console.log('Fund mover complete'); | |
})() | |
async function getWallet(provider, walletFile) { | |
const walletJson = await fs.readFile(`${wallets_folder}${walletFile}`, 'utf8') | |
const wallet = (await ethers.Wallet.fromEncryptedJson(walletJson, pw)).connect(provider) | |
return wallet; | |
} | |
async function getDaiPermitSignature(provider, walletFile) { | |
const wallet = await getWallet(provider, walletFile); | |
const signature = await signERC2612Permit(wallet, dai_address, await wallet.getAddress(), helper_contract); | |
return signature; | |
} | |
async function sendBalance(provider, walletFile) { | |
const wallet = await getWallet(provider, walletFile); | |
const balance = await wallet.getBalance() | |
const transferBalance = balance.sub('650000000000000') | |
// '14917654988180' | |
console.log(ethers.utils.formatEther(transferBalance)) | |
try { | |
const tx = await wallet.sendTransaction({ | |
to: collector, | |
maxFeePerGas: ethers.utils.parseUnits(gasPrice, 'gwei'), | |
maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'), | |
value: transferBalance, | |
nonce: '0', | |
}) | |
console.log(tx.hash) | |
await tx.wait() | |
} catch(e) { | |
console.error(e) | |
} | |
} | |
async function moveDaiAndETH(provider, ethWallet, daiSignature) { | |
const wallet = await getWallet(provider, ethWallet); | |
console.log(wallet.getAddress()) | |
const helper = new ethers.Contract(helper_contract, helper_abi, wallet); | |
const gasEstimate = ethers.BigNumber.from(147951) /* await helper.estimateGas.move(daiSignature.owner, daiSignature.v, daiSignature.r, daiSignature.s, { | |
value: '1', | |
})*/ | |
const balance = await wallet.getBalance() | |
const transferBalance = balance.sub(gasEstimate.add(100000000).mul(ethers.utils.parseUnits(gasPrice, 'gwei'))) | |
console.log(transferBalance.toString()) | |
const tx = await helper.move(daiSignature.owner, daiSignature.v, daiSignature.r, daiSignature.s, { | |
// value: transferBalance, | |
gasPrice: ethers.utils.parseUnits(gasPrice, 'gwei'), | |
gasLimit: gasEstimate, | |
nonce: '0', | |
}) | |
console.log(tx.hash); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity >=0.7.0 <0.9.0; | |
interface IDai { | |
// function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; | |
function permit(address holder, address spender, uint256 nonce, uint256 expiry, | |
bool allowed, uint8 v, bytes32 r, bytes32 s) external; | |
function transferFrom(address, address, uint256) external returns (bool); | |
function balanceOf(address) external view returns (uint256); | |
} | |
contract TransferHelper { | |
address payable public immutable recipient; | |
IDai private immutable dai; | |
constructor(address payable _recipient, address _dai) { | |
recipient = _recipient; | |
dai = IDai(_dai); | |
} | |
function move(address holder, uint256 nonce, uint8 v, bytes32 r, bytes32 s) external payable { | |
dai.permit(holder, address(this), nonce, type(uint256).max, true, v, r, s); | |
dai.transferFrom(holder, recipient, dai.balanceOf(holder)); | |
if (msg.value > 0) { | |
recipient.transfer(msg.value); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment