mirror of git3://git3.w3q/git3-cli
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
9.2 KiB
TypeScript
281 lines
9.2 KiB
TypeScript
import { mkdirSync, readdirSync, readFileSync, writeFileSync, rmSync } from "fs"
|
|
import { ethers } from "ethers"
|
|
import { Command } from "commander"
|
|
import bip39 from "bip39"
|
|
import inquirer from "inquirer"
|
|
import { importActions, generateActions } from "./actions.js"
|
|
import network from "../config/evm-network.js"
|
|
import { getWallet, randomRPC } from "../common/wallet.js"
|
|
import { parseGit3URI } from "../common/git3-protocol.js"
|
|
import { TxManager } from "../common/tx-manager.js"
|
|
const program = new Command()
|
|
|
|
program.name("git3").description("git3 mangement tool").version("0.1.0")
|
|
|
|
program
|
|
.command("generate")
|
|
.alias("gen")
|
|
.alias("new")
|
|
.description("generate a cryto wallet to use git3")
|
|
.action(() => {
|
|
inquirer.prompt(generateActions).then((answers) => {
|
|
const { keyType, name } = answers
|
|
const walletType =
|
|
keyType === "private key" ? "privateKey" : "mnemonic"
|
|
|
|
const keyPath = process.env.HOME + "/.git3/keys"
|
|
mkdirSync(keyPath, { recursive: true })
|
|
|
|
if (readdirSync(keyPath).includes(name)) {
|
|
console.error(`wallet ${name} already exists`)
|
|
return
|
|
}
|
|
|
|
const mnemonic = bip39.generateMnemonic()
|
|
const wallet =
|
|
keyType === "private key"
|
|
? ethers.Wallet.createRandom()
|
|
: ethers.Wallet.fromMnemonic(mnemonic)
|
|
|
|
const content = `${walletType}\n${
|
|
keyType === "private key" ? wallet.privateKey : mnemonic
|
|
}\n`
|
|
writeFileSync(`${keyPath}/${name}`, content)
|
|
return
|
|
})
|
|
})
|
|
|
|
program
|
|
.command("list", { isDefault: true })
|
|
.alias("ls")
|
|
.description("list all wallets in user folder ~/.git3/keys")
|
|
.option("-r, --raw", "output raw wallet data with pravate key / mnemonic")
|
|
.action((params) => {
|
|
const keyPath = process.env.HOME + "/.git3/keys"
|
|
mkdirSync(keyPath, { recursive: true })
|
|
const wallets = readdirSync(keyPath)
|
|
|
|
if (wallets.length === 0) {
|
|
console.log("No wallet found, you can generate one use <git3 new>")
|
|
}
|
|
|
|
wallets.forEach((file) => {
|
|
const content = readFileSync(`${keyPath}/${file}`).toString()
|
|
|
|
if (params.raw) {
|
|
console.log(`[${file}]`)
|
|
console.log(
|
|
` ${content.split("\n")[0]} - ${content.split("\n")[1]}`
|
|
)
|
|
console.log("\t")
|
|
return
|
|
}
|
|
|
|
console.log(`[${file}]`)
|
|
const [walletType, key] = content.split("\n")
|
|
const etherWallet =
|
|
walletType === "privateKey"
|
|
? new ethers.Wallet(key)
|
|
: ethers.Wallet.fromMnemonic(key)
|
|
const address = etherWallet.address
|
|
console.log(`address: ${address}`)
|
|
console.log("\t")
|
|
})
|
|
})
|
|
|
|
program
|
|
.command("import")
|
|
.description("import a wallet from a private key or mnemonic")
|
|
.action(() => {
|
|
inquirer.prompt(importActions).then((answers) => {
|
|
const { keyType, key, name } = answers
|
|
const walletType =
|
|
keyType === "private key" ? "privateKey" : "mnemonic"
|
|
const keyPath = process.env.HOME + "/.git3/keys"
|
|
mkdirSync(keyPath, { recursive: true })
|
|
|
|
if (readdirSync(keyPath).includes(name)) {
|
|
console.error(`wallet ${name} already exists`)
|
|
return
|
|
}
|
|
|
|
const content = `${walletType}\n${key}\n`
|
|
writeFileSync(`${keyPath}/${name}`, content)
|
|
return
|
|
})
|
|
})
|
|
|
|
program
|
|
.command("delete")
|
|
.description("delete a wallet")
|
|
.action(() => {
|
|
const keyPath = process.env.HOME + "/.git3/keys"
|
|
mkdirSync(keyPath, { recursive: true })
|
|
const wallets = readdirSync(keyPath)
|
|
|
|
if (wallets.length === 0) {
|
|
console.error(
|
|
"No wallet found, you can generate one with `git3 generate`"
|
|
)
|
|
return
|
|
}
|
|
|
|
inquirer
|
|
.prompt([
|
|
{
|
|
type: "list",
|
|
name: "wallet",
|
|
message: "Select wallet to delete",
|
|
choices: wallets,
|
|
},
|
|
])
|
|
.then((answers) => {
|
|
const { wallet } = answers
|
|
rmSync(`${keyPath}/${wallet}`)
|
|
})
|
|
})
|
|
|
|
program
|
|
.command("create")
|
|
.argument("<uri>", "ex: default@git3.w3q/repo_name")
|
|
.description("create a new repo")
|
|
.action(async (uri) => {
|
|
if (!uri.startsWith("git3://")) {
|
|
uri = "git3://" + uri
|
|
}
|
|
const protocol = parseGit3URI(uri)
|
|
let owner = await protocol.contract.repoNameToOwner(
|
|
Buffer.from(protocol.repoName)
|
|
)
|
|
|
|
if (owner != "0x0000000000000000000000000000000000000000") {
|
|
console.error(`repo ${protocol.repoName} already exists`)
|
|
return
|
|
}
|
|
console.log(
|
|
`creating repo ${protocol.repoName} on ${protocol.netConfig.name}...`
|
|
)
|
|
const txManager = new TxManager(
|
|
protocol.contract,
|
|
protocol.chainId,
|
|
protocol.netConfig.txConst
|
|
)
|
|
let receipt = await txManager.SendCall("createRepo", [
|
|
Buffer.from(protocol.repoName),
|
|
])
|
|
if (
|
|
protocol.netConfig.explorers &&
|
|
protocol.netConfig.explorers.length > 0
|
|
) {
|
|
console.log(
|
|
protocol.netConfig.explorers[0].url.replace(/\/+$/, "") +
|
|
"/tx/" +
|
|
receipt.transactionHash
|
|
)
|
|
} else {
|
|
console.log(receipt.transactionHash)
|
|
}
|
|
console.log(`repo ${protocol.repoName} created.`)
|
|
})
|
|
|
|
program
|
|
.command("info")
|
|
.argument("[wallet]", "wallet you want to get info", "default")
|
|
.description("get info of a wallet")
|
|
.action((wallet) => {
|
|
let etherWallet = getWallet(wallet)
|
|
|
|
const address = etherWallet.address
|
|
|
|
console.log(`wallet: ${wallet}`)
|
|
console.log(`address: ${address}`)
|
|
|
|
for (let [_, net] of Object.entries(network)) {
|
|
const provider = new ethers.providers.JsonRpcProvider(
|
|
randomRPC(net.rpc)
|
|
)
|
|
const balance = provider.getBalance(address)
|
|
balance.then((res) => {
|
|
console.log(
|
|
`[${net.name}] balance: ${ethers.utils.formatUnits(
|
|
res,
|
|
net.nativeCurrency.decimals
|
|
)} ${net.nativeCurrency.symbol}`
|
|
)
|
|
})
|
|
}
|
|
})
|
|
|
|
program
|
|
.command("clear")
|
|
.description("clear pending nonce")
|
|
.argument("<uri>", "ex: default@git3.w3q")
|
|
.argument("[num]", "number of pending nonce to clear", 1)
|
|
.action(async (uri, num) => {
|
|
if (!uri.startsWith("git3://")) {
|
|
uri = "git3://" + uri
|
|
}
|
|
const protocol = parseGit3URI(uri, { skipRepoName: true })
|
|
const txManager = new TxManager(
|
|
protocol.contract,
|
|
protocol.chainId,
|
|
protocol.netConfig.txConst
|
|
)
|
|
let nonce = await protocol.wallet.getTransactionCount()
|
|
console.log(`current nonce: ${nonce}`)
|
|
await txManager.clearPendingNonce(num)
|
|
nonce = await protocol.wallet.getTransactionCount()
|
|
console.log(`current nonce: ${nonce}`)
|
|
})
|
|
|
|
// Todo: set-wallet temporarily useless
|
|
// program
|
|
// .command("set-wallet")
|
|
// .alias("set")
|
|
// .argument("<git3>", "git3 remote")
|
|
// .argument("[wallet]", "wallet you want to bind", "default")
|
|
// .description("bind git3 remotes with a wallet")
|
|
// .action((git3, wallet) => {
|
|
// const currentConfig = parse.sync()
|
|
|
|
// const existingRemote = currentConfig[`remote "${git3}"`]
|
|
// const keyPath = process.env.HOME + "/.git3/keys"
|
|
// mkdirSync(keyPath, { recursive: true })
|
|
|
|
// if (!existsSync(`${keyPath}/${wallet}`)) {
|
|
// console.error(
|
|
// `wallet ${wallet} not found, use <git3 new> to generate one`
|
|
// )
|
|
// return
|
|
// }
|
|
|
|
// if (existingRemote) {
|
|
// const newConfig = {
|
|
// ...currentConfig,
|
|
// [`remote "${git3}"`]: {
|
|
// ...existingRemote,
|
|
// wallet,
|
|
// },
|
|
// }
|
|
|
|
// // console.log(newConfig)
|
|
// // const writer = createWriteStream('config', 'w')
|
|
// let newConfigText = ""
|
|
// Object.keys(newConfig).forEach((key) => {
|
|
// newConfigText += `[${key}]\n`
|
|
// Object.keys(newConfig[key]).forEach((subKey) => {
|
|
// newConfigText += `\t${subKey} = ${newConfig[key][subKey]}\n`
|
|
// })
|
|
// })
|
|
// let path = parse.resolveConfigPath("global") || ""
|
|
// writeFileSync(path, newConfigText)
|
|
// } else {
|
|
// console.error(`remote ${git3} not found`)
|
|
// console.error(
|
|
// "you can add a remote with `git remote add <name> <url>"
|
|
// )
|
|
// }
|
|
// })
|
|
|
|
program.parse()
|