-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 52a3eb1
Showing
13 changed files
with
1,266 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
ETH_SEPOLIA_RPC = 'https://endpoints.omniatech.io/v1/eth/sepolia/public' # 11155111 | ||
ARB_SEPOLIA_RPC = 'https://sepolia-rollup.arbitrum.io/rpc' # 421614 | ||
STYLUS_TESTNET_RPC = 'https://stylus-testnet.arbitrum.io/rpc' # 23011913 | ||
|
||
# Deposit ETH from Sepolia to Arbitrum Sepolia | ||
ARB_SEPOLIA_INBOX_ROUTER = '0xaAe29B0366299461418F5324a79Afc425BE5ae21' | ||
# Deposit ETH from Arbitrum Sepolia to Arbitrum Stylus Test | ||
ARB_STYLUS_INBOX_ROUTER = '0xe1e3b1CBaCC870cb6e5F4Bdf246feB6eB5cD351B' | ||
# Contact address for mint Omnibase nft to Arbitrum Stylus Testnet | ||
STYLUS_OMNIBASE_CONTRACT = '0xA02573c4Ad15c16b48f10842aaC9c9eA405B65A3' | ||
|
||
|
||
EXP_ETH_SEPOLIA = 'https://sepolia.etherscan.io' | ||
EXP_ARB_SEPOLIA = 'https://sepolia-explorer.arbitrum.io' | ||
EXP_STL_ARBITRUM = 'https://stylus-testnet-explorer.arbitrum.io' |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Auto detect text files and perform LF normalization | ||
* text=auto |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: TypeScript Build | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout Repository | ||
uses: actions/checkout@v3 | ||
|
||
- name: Setup Node.js | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 20 | ||
|
||
- name: Install Dependencies | ||
run: npm i | ||
|
||
- name: Set Global TypeScript | ||
run: npm i -g typescript | ||
|
||
- name: Build TS | ||
run: tsc --project tsconfig.json | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Private files | ||
seeds.txt | ||
private_keys.txt | ||
proxies.txt | ||
.env | ||
# Compilled js | ||
*.js | ||
!_*.js | ||
# Dependency directories | ||
node_modules/ | ||
# yarn v2 | ||
.yarn/cache | ||
.yarn/unplugged | ||
.yarn/build-state.yml | ||
.yarn/install-state.gz | ||
.pnp.* | ||
test.ts | ||
test.ts |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
[![Status](https://img.shields.io/badge/status-active-success.svg)](https://github.com/whonion/ts-stylus-bridger-and-minter/blob/main/) [![Build TS](https://github.com/whonion/ts-stylus-bridger-and-minter/actions/workflows/build.yml/badge.svg)](https://github.com/whonion/ts-stylus-bridger-and-minter/actions/workflows/test.yml) ![Node Version](https://img.shields.io/badge/Node.js-20.6.1-blue.svg) ![Ethers Version](https://img.shields.io/badge/ethers-5.7.2-red.svg) [![HitCount](https://hits.dwyl.com/whonion/ts-stylus-bridger-and-minter.svg)](https://hits.dwyl.com/whonion/ts-stylus-bridger-and-minter)</br> | ||
## arbitrum-stylus-bridger-and-minter | ||
TypeScript impelementation of Arbitrum Stylus Testnet Bridger and Omnibase NFT minter | ||
|
||
`main.js` preview <br>![ts-stylus-bridger-and-minter](https://github.com/whonion/ts-stylus-bridger-and-minter/blob/main/.github/preview.png?raw=true)<br> | ||
|
||
### Install `Node.js` | ||
```sh | ||
sudo apt install git | ||
sudo apt install nodejs | ||
sudo apt install npm | ||
node -v | ||
npm -v | ||
``` | ||
### Clone repo and install dependencies | ||
```sh | ||
git clone https://github.com/whonion/ts-stylus-bridger-and-minter.git | ||
cd ts-stylus-bridger-and-minter | ||
npm i | ||
npm i -g typescript | ||
tsc --project tsconfig.json | ||
|
||
``` | ||
## What's do script ? | ||
### Bridge Funds | ||
- Bridge Funds from Sepolia Testnet to Arbitrum Sepolia via [bridge.arbitrum.io](https://bridge.arbitrum.io) | ||
- Bridge Funds from Arbitrum Sepolia to Arbitrum Stylus Testnet via [bridge.arbitrum.io](https://bridge.arbitrum.io) | ||
- Mint Omnibase NFT (Powered by Layer Zero) to Arbitrum Stylus | ||
## Run Script | ||
```sh | ||
node main.js | ||
``` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { ethers, BigNumber } from 'ethers'; | ||
import dotenv from 'dotenv'; | ||
import fs from 'fs'; | ||
|
||
dotenv.config(); | ||
const contractABI = [ | ||
{ | ||
name: "depositEth", | ||
outputs: [], | ||
payable: true, | ||
stateMutability: "payable", | ||
type: "function", | ||
}, | ||
]; | ||
// Load private keys from private_keys.txt | ||
const privateKeys = fs.readFileSync('private_keys.txt', 'utf-8').split('\n').map(key => key.trim()).filter(Boolean); | ||
|
||
// Ethereum RPC and contract addresses with default values | ||
const ethRpc = process.env.ETH_SEPOLIA_RPC || 'https://endpoints.omniatech.io/v1/eth/sepolia/public'; // Default RPC URL | ||
const ethContractAddress = process.env.ARB_SEPOLIA_INBOX_ROUTER || '0xaAe29B0366299461418F5324a79Afc425BE5ae21'; // Default contract address | ||
|
||
// Arbitrum RPC and contract addresses with default values | ||
const arbRpc = process.env.ARB_SEPOLIA_RPC || 'https://sepolia-rollup.arbitrum.io/rpc'; // Default RPC URL | ||
const arbContractAddress = process.env.ARB_STYLUS_INBOX_ROUTER || '0xe1e3b1CBaCC870cb6e5F4Bdf246feB6eB5cD351B'; // Default contract address | ||
|
||
// Ethereum Sepolia explorer URL | ||
const EXP_ETH_SEPOLIA = process.env.EXP_ETH_SEPOLIA || 'https://sepolia.etherscan.io'; // Default Arbitrum Sepolia Explorer URL | ||
// Arbitrum Sepolia explorer URL | ||
const EXP_ARB_SEPOLIA = process.env.EXP_ARB_SEPOLIA || 'https://sepolia-explorer.arbitrum.io'; // Default Arbitrum Sepolia Explorer URL | ||
|
||
// Define gasLimit, maxFeePerGas, and maxPriorityFeePerGas here | ||
const gasLimit = ethers.BigNumber.from('120000'); | ||
const maxFeePerGas = ethers.BigNumber.from('3000000000'); | ||
const maxPriorityFeePerGas = ethers.BigNumber.from('250000000'); | ||
|
||
// Function to send ETH to the contract using the depositEth function | ||
async function sendEthToContract(privateKey: string, rpcUrl: string, ContractAddress: string, sendAmount: ethers.BigNumber, exp_url: string) { | ||
// Create a provider with the provided RPC URL | ||
const ethProvider = new ethers.providers.JsonRpcProvider(rpcUrl); | ||
|
||
const wallet = new ethers.Wallet(privateKey, ethProvider); | ||
|
||
try { | ||
// Corrected ABI to call the 'depositEth' function | ||
const contract = new ethers.Contract(ContractAddress, contractABI, wallet); | ||
|
||
const nonce = await wallet.getTransactionCount(); | ||
|
||
// Transaction data | ||
const tx = await contract.depositEth({ | ||
value: sendAmount, // Send ETH amount as a BigNumber | ||
gasLimit: gasLimit, // Gas limit as a BigNumber | ||
maxFeePerGas: maxFeePerGas, // Max fee per gas as a BigNumber | ||
maxPriorityFeePerGas: maxPriorityFeePerGas, // Max priority fee per gas as a BigNumber | ||
nonce: nonce, // Nonce as a regular number | ||
|
||
}); | ||
|
||
// Wait for the transaction to be mined | ||
const receipt = await tx.wait(); | ||
|
||
if (receipt.status === 0) { | ||
// Transaction failed (reverted) | ||
console.error(`⛔ Transaction reverted. Error message:\n ${receipt.logs[0]?.data}`); | ||
} else { | ||
console.log(`Sent ${ethers.utils.formatEther(sendAmount)} ETH from ${wallet.address} to the contract: 📃 ${ContractAddress} `); | ||
console.log(`View on Blockchain explorer: ${exp_url}/tx/${tx.hash}`); | ||
if (exp_url === EXP_ETH_SEPOLIA) { | ||
console.log("✅ Successfully Bridged to Arbitrum Sepolia"); | ||
} else { | ||
console.log("✅ Successfully Bridged to Arbitrum Stylus"); | ||
} | ||
} | ||
} catch (error) { | ||
console.error(`❌ Error sending ETH from address ${wallet.address} to the contract: 📃 ${ContractAddress}`); | ||
} | ||
|
||
} | ||
// Function to sleep for a specified duration in milliseconds | ||
function sleep(ms: number): Promise<void> { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
export async function sendEth(ethValue: BigNumber) { | ||
for (const privateKey of privateKeys) { | ||
let explorer: string = EXP_ETH_SEPOLIA; | ||
await sendEthToContract(privateKey, ethRpc, ethContractAddress, ethValue, explorer).catch((error) => { | ||
console.error('❌ Error bridge ETH via contract: 📃 ${contractAddress}', error); | ||
}); | ||
} | ||
|
||
// Wait for the first cycle to complete before starting the second one with a delay of 6000 ms | ||
await new Promise((resolve) => setTimeout(resolve, 6000)); | ||
|
||
for (const privateKey of privateKeys) { | ||
let explorer: string = EXP_ARB_SEPOLIA; | ||
await sendEthToContract(privateKey, arbRpc, arbContractAddress, ethValue, explorer).catch((error) => { | ||
console.error('❌ Error sending ETH to the contract: 📃 ${contractAddress}', error); | ||
}); | ||
} | ||
} | ||
|
||
|
||
|
||
//sendEth(); |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { ethers, BigNumber } from 'ethers'; | ||
import { sendEth } from './bridge.js'; | ||
import { mintNFTs } from './mint.js'; | ||
import readline from 'readline'; | ||
|
||
const rl = readline.createInterface({ | ||
input: process.stdin, | ||
output: process.stdout | ||
}); | ||
|
||
async function displayMenu() { | ||
console.log("Select action:"); | ||
console.log("1. Bridge ETH from Ethereum Sepolia to Arbitrum Sepolia and next Bridge to Arbitrum Stylus Testnet"); | ||
console.log("2. Mint Omnibase NFT to Arbitrum Stylus Test"); | ||
console.log("0. Exit"); | ||
} | ||
|
||
async function performAction(action: number) { | ||
switch (action) { | ||
case 1: | ||
rl.question("How many ETH do you want to send? ", async (amountETH) => { | ||
const ethValue = ethers.BigNumber.from(ethers.utils.parseEther(amountETH)); | ||
console.log("🌐 Starting the script to bridge ETH via https://bridge.arbitrum.io"); | ||
await sendEth(ethValue); | ||
console.log("ETH bridging complete."); | ||
continueMenu(); | ||
}); | ||
break; | ||
case 2: | ||
rl.question("How many NFTs do you want to mint? ", async (count) => { | ||
const mintAmount = ethers.BigNumber.from(count); | ||
console.log("🌐 Starting the script to mint NFT via https://power.omnibase.xyz/"); | ||
await mintNFTs(mintAmount); | ||
console.log("NFT minting complete."); | ||
continueMenu(); | ||
}); | ||
break; | ||
case 0: | ||
console.log("Exiting..."); | ||
rl.close(); | ||
break; | ||
default: | ||
console.log("Invalid selection. Please enter the correct action."); | ||
continueMenu(); | ||
break; | ||
} | ||
} | ||
|
||
async function continueMenu() { | ||
await displayMenu(); | ||
|
||
rl.question("Enter your choice: ", (choice) => { | ||
const action = parseInt(choice); | ||
|
||
if (isNaN(action)) { | ||
console.log("Incorrect choice. Please enter the correct number."); | ||
continueMenu(); | ||
} else { | ||
if (action === 0) { | ||
console.log("Exiting..."); | ||
rl.close(); | ||
} else { | ||
performAction(action); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
async function startMenu() { | ||
await continueMenu(); | ||
} | ||
|
||
// Start menu | ||
startMenu(); |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { BigNumber, ethers } from 'ethers'; | ||
import dotenv from 'dotenv'; | ||
import fs from 'fs'; | ||
|
||
dotenv.config(); | ||
|
||
const mintABI = [ | ||
{ | ||
type: "function", | ||
stateMutability: "payable", | ||
outputs: [], | ||
name: "mint", | ||
inputs: [ | ||
{ | ||
type: "uint256", | ||
name: "_mintAmount", | ||
internalType: "uint256", | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
// Load private keys from private_keys.txt | ||
const privateKeys = fs.readFileSync('private_keys.txt', 'utf-8').split('\n').map(key => key.trim()).filter(Boolean); | ||
// Arbitrum Stylus Testnet RPC and contract addresses with default values | ||
const stylusRpc = process.env.STYLUS_TESTNET_RPC || 'https://stylus-testnet.arbitrum.io/rpc'; // Default RPC URL | ||
const stylusContractAddress = process.env.STYLUS_OMNIBASE_CONTRACT || '0xA02573c4Ad15c16b48f10842aaC9c9eA405B65A3'; // Default contract address | ||
// Arbitrum Stylus explorer URL | ||
const EXP_STL_ARBITRUM = process.env.EXP_STL_ARBITRUM || 'https://stylus-testnet-explorer.arbitrum.io'; // Default Arbitrum Sepolia Explorer URL | ||
|
||
|
||
|
||
let exp_url = EXP_STL_ARBITRUM | ||
// Function to send ETH to the contract using the mint function | ||
async function mintNFT(privateKey: string, rpcUrl: string, contractAddress: string, mintAmount: ethers.BigNumber) { | ||
// Create a provider with the provided RPC URL | ||
const ethProvider = new ethers.providers.JsonRpcProvider(rpcUrl); | ||
|
||
const wallet = new ethers.Wallet(privateKey, ethProvider); | ||
|
||
try { | ||
// Create a contract instance with the mint ABI | ||
const contract = new ethers.Contract(contractAddress, mintABI, wallet); | ||
|
||
const nonce = await wallet.getTransactionCount(); | ||
|
||
// Define gasLimit, maxFeePerGas, and maxPriorityFeePerGas mint cost here | ||
const maxFeePerGas = ethers.BigNumber.from('1650000000'); // 1.62 Gwei | ||
const maxPriorityFeePerGas = ethers.BigNumber.from('1000000000'); // 1 Gwei | ||
const gasLimit = ethers.BigNumber.from('800000'); // Adjust as needed | ||
const additionalValue = ethers.utils.parseEther('0.00023'); // Additional value in ETH | ||
// Calculate the total value to send (including gas fees) | ||
const gasFee = maxFeePerGas.mul(gasLimit); | ||
const priorityFee = maxPriorityFeePerGas.mul(gasLimit); | ||
const totalValue = gasFee.add(priorityFee).add(additionalValue); | ||
//const mintAmount = ethers.BigNumber.from('1'); // Set count of NFT | ||
const tx = await contract.mint(mintAmount,{ | ||
value: ethers.BigNumber.from(totalValue), // Send the total value | ||
gasLimit: gasLimit, | ||
maxFeePerGas: maxFeePerGas, // Set gas price here | ||
maxPriorityFeePerGas: maxPriorityFeePerGas, | ||
nonce: nonce, | ||
}); | ||
|
||
const receipt = await tx.wait(); | ||
|
||
if (receipt.status === 0) { | ||
// Transaction failed (reverted) | ||
console.error(`⛔ Transaction reverted. Error message:\n ${receipt.logs[0]?.data}`); | ||
} else { | ||
console.log(`✅ Successfuly minted ${ethers.utils.formatUnits(mintAmount, 0)} NFTs from ${wallet.address} to the contract: 📃 ${contractAddress}`); | ||
|
||
console.log(`View on Blockchain explorer: ${exp_url}/tx/${tx.hash}`); | ||
} | ||
} catch (error) { | ||
console.error(`❌ Error minting NFT from address ${wallet.address} to the contract: 📃 ${contractAddress}\n`,error); | ||
} | ||
} | ||
|
||
// Function to sleep for a specified duration in milliseconds | ||
function sleep(ms: number): Promise<void> { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
|
||
//const mintAmount = ethers.BigNumber.from('1'); // Set count of NFT | ||
|
||
// Call the function to mint NFTs | ||
export async function mintNFTs(mintAmount:BigNumber) { | ||
for (const privateKey of privateKeys) { | ||
await mintNFT(privateKey, stylusRpc, stylusContractAddress, mintAmount).catch((error) => { | ||
console.error('❌ Error minting NFT:', error); | ||
}); | ||
} | ||
|
||
sleep(5000); | ||
} | ||
//mintNFTs(); |
Oops, something went wrong.