Skip to content

Commit

Permalink
fix: multiple things
Browse files Browse the repository at this point in the history
  • Loading branch information
janek26 committed Dec 6, 2022
1 parent 037b61f commit 7542834
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 80 deletions.
17 changes: 3 additions & 14 deletions actions/transferAll/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,15 @@ import { Account } from "../../ui/pickAccounts";
import TOKENS from "../../default-tokens.json";
import { Ora } from "ora";
import { oraLog } from "../../oraLog";
import { getNonce } from "./getNonce";
import { estimateFee, execute } from "../../execute";

export async function transferAll(acc: Account, newAddress: string, ora: Ora) {
const { privateKey } = acc;
if (!privateKey) {
throw new Error("No private key for account to credit");
}
const keyPair = ec.getKeyPair(privateKey);
const starkKey = ec.getStarkKey(keyPair);
if (!BigNumber.from(acc.signer).eq(starkKey)) {
throw new Error(
"Account cant be controlled with the selected private key or seed"
);
}

const provider = new SequencerProvider({ network: acc.networkId as any });
const account = new SNAccount(provider, acc.address.toLowerCase(), keyPair);
const tokens = TOKENS.filter((t) => t.network === acc.networkId);
const calls = Object.entries(acc.balances)
.filter(([, balance]) => utils.parseEther(balance).gt(0))
Expand All @@ -53,8 +45,7 @@ export async function transferAll(acc: Account, newAddress: string, ora: Ora) {
});

if (calls.length) {
const nonce = await getNonce(acc.address, acc.networkId); // use this to get the nonce, as this covers old and new way of getting nonce
const { suggestedMaxFee } = await account.estimateFee(calls, { nonce });
const { suggestedMaxFee } = await estimateFee(acc, calls);

const callsWithFee = calls.map((c) => {
const tokenDetails = tokens.find((t) => t.symbol === "ETH");
Expand Down Expand Up @@ -82,9 +73,7 @@ export async function transferAll(acc: Account, newAddress: string, ora: Ora) {
});

// execute with suggested max fee substracted from a potential eth transfer
const transaction = await account.execute(callsWithFee, undefined, {
maxFee: suggestedMaxFee,
});
const transaction = await execute(acc, callsWithFee);

oraLog(ora, `Transaction ${transaction.transaction_hash} created`);

Expand Down
25 changes: 0 additions & 25 deletions actions/transferAll/getNonce.ts

This file was deleted.

20 changes: 9 additions & 11 deletions actions/transferAll/ui.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import ora from "ora";
import prompts from "prompts";
import { ValidationError } from "yup";
import { detectAccountIssues, fixAccountIssues } from "../../issues";
import { addressSchema } from "../../schema";
import { Account } from "../../ui/pickAccounts";
import { transferAll } from "./core";

export async function showTransferAll(
accounts: Account[],
networkId: "mainnet-alpha" | "goerli-alpha"
) {
export async function showTransferAll(accounts: Account[]) {
const { toAddress } = await prompts(
{
type: "text",
Expand All @@ -32,11 +28,7 @@ export async function showTransferAll(
}
);

const spinner = ora("Detecting potential issues").start();

const issues = await detectAccountIssues(accounts);

await fixAccountIssues(accounts, networkId, issues);
const spinner = ora("Transfering tokens").start();

const transferResults = await Promise.allSettled(
accounts.map(async (acc) => transferAll(acc, toAddress, spinner))
Expand All @@ -48,5 +40,11 @@ export async function showTransferAll(
}
});

spinner.succeed("All tokens transferred");
if (transferResults.every((result) => result.status === "fulfilled")) {
spinner.succeed("Transfers complete");
} else if (transferResults.some((result) => result.status === "fulfilled")) {
spinner.fail("Some transfers failed");
} else {
spinner.fail("All transfers failed");
}
}
58 changes: 58 additions & 0 deletions execute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
SequencerProvider as NewProvider,
Account as NewAccount,
} from "starknet-490";
import {
Call,
SequencerProvider as OldProvider,
Account as OldAccount,
ec,
} from "starknet";
import { BigNumber } from "ethers";
import { Account } from "./ui/pickAccounts";

export async function estimateFee(account: Account, call: Call[] | Call) {
const calls = Array.isArray(call) ? call : [call];
const lowerCaseAddress = account.address.toLowerCase();
const keyPair = ec.getKeyPair(account.privateKey);
const starkKey = ec.getStarkKey(keyPair);
if (!BigNumber.from(account.signer).eq(starkKey)) {
throw new Error(
"Account cant be controlled with the selected private key or seed"
);
}
try {
const oldProvider = new OldProvider({ network: account.networkId as any });
const a = new OldAccount(oldProvider, lowerCaseAddress, keyPair);
return await a.estimateFee(calls);
} catch {
const newProvider = new NewProvider({ network: account.networkId as any });
const a = new NewAccount(newProvider, lowerCaseAddress, keyPair);
return a.estimateFee(calls);
}
}

export async function execute(account: Account, call: Call[] | Call) {
const calls = Array.isArray(call) ? call : [call];
const lowerCaseAddress = account.address.toLowerCase();
const keyPair = ec.getKeyPair(account.privateKey);
const starkKey = ec.getStarkKey(keyPair);
if (!BigNumber.from(account.signer).eq(starkKey)) {
throw new Error(
"Account cant be controlled with the selected private key or seed"
);
}
try {
const oldProvider = new OldProvider({ network: account.networkId as any });
const a = new OldAccount(oldProvider, lowerCaseAddress, keyPair);
return await a.execute(calls);
} catch (e) {
console.warn("old failed", e);
const newProvider = new NewProvider({ network: account.networkId as any });
const a = new NewAccount(newProvider, lowerCaseAddress, keyPair);
return a.execute(calls).catch((e) => {
console.warn("new failed", e);
throw e;
});
}
}
51 changes: 35 additions & 16 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { unionWith } from "lodash";
import { showTransferAll } from "./actions/transferAll/ui";
import { askForExtraAccounts, extraAccount } from "./ui/extraAccount";
import { equalSigner, getDefaultSigners } from "./genSigners";
import { detectAccountIssues, fixAccountIssues } from "./issues";
import { ec } from "starknet";

program
.name("Argent X CLI")
Expand Down Expand Up @@ -38,11 +40,11 @@ program.parse();
spinner.succeed("Found " + accounts.length + " wallets");

if (accounts.length === 0) {
accounts = await extraAccount(network, privateKey);
accounts = await extraAccount(network);
} else if (await askForExtraAccounts()) {
accounts = unionWith(
accounts,
await extraAccount(network, privateKey),
await extraAccount(network),
(a, b) => a.address === b.address
);
}
Expand All @@ -59,25 +61,38 @@ program.parse();
}));

// find missing signers
if (seed && accountWithSigner.some((x) => !x.privateKey)) {
if (accountWithSigner.some((x) => !x.privateKey)) {
spinner.start("Trying to find missing private keys");
const defaultSigners = getDefaultSigners(seed);
accountWithSigner
.filter((x) => !x.privateKey)
.forEach((x) => {
const signer = defaultSigners.find(
(y) => x.signer && equalSigner(x.signer, y.signer)
);
if (signer) {
x.privateKey = signer.privateKey;
}
});
if (seed) {
const defaultSigners = getDefaultSigners(seed);
accountWithSigner
.filter((x) => !x.privateKey)
.forEach((x) => {
const signer = defaultSigners.find(
(y) => x.signer && equalSigner(x.signer, y.signer)
);
if (signer) {
x.privateKey = signer.privateKey;
}
});
}
if (privateKey) {
const defaultSigner = ec.getStarkKey(ec.getKeyPair(privateKey));
spinner.info(`Public key: ${defaultSigner}`);
accountWithSigner
.filter((x) => !x.privateKey)
.forEach((x) => {
if (x.signer && equalSigner(x.signer, defaultSigner)) {
x.privateKey = privateKey;
}
});
}
if (accountWithSigner.some((x) => !x.privateKey)) {
spinner.warn(
"Could not find all private keys. Continuing with missing private keys"
);
} else {
spinner.succeed("Found all private keys");
spinner.succeed("Found all signers");
}
}

Expand All @@ -88,7 +103,11 @@ program.parse();

display(filteredAccountWithSigner);

await showTransferAll(filteredAccountWithSigner, network);
const issues = await detectAccountIssues(filteredAccountWithSigner);

await fixAccountIssues(accountWithSigner, network, issues);

await showTransferAll(filteredAccountWithSigner);
})().catch((e) => {
console.error("An error occured", e);
process.exit(1);
Expand Down
12 changes: 8 additions & 4 deletions issues/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { uniqBy } from "lodash";
import prompts from "prompts";
import { truncateAddress } from "../addressFormatting";
import { Account } from "../ui/pickAccounts";
import { detect as detectOldHashAlgo } from "./oldHashAlgo/detect";
import { fix as fixOldHashAlgo } from "./oldHashAlgo/fix";
import { detect as detectSigner0 } from "./signer0/detect";
import { fix as fixSigner0 } from "./signer0/fix";

interface IssuesMap {
oldHashAlgo?: string[];
signer0?: string[];
}

export async function detectAccountIssues(
accounts: Account[]
): Promise<IssuesMap> {
const oldHashAlgo = await detectOldHashAlgo(accounts);
return { oldHashAlgo };
const signer0 = await detectSigner0(accounts);
return { oldHashAlgo, signer0 };
}

export async function fixAccountIssues(
Expand All @@ -25,4 +26,7 @@ export async function fixAccountIssues(
if (oldHashAlgo?.length && oldHashAlgo?.length > 0) {
await fixOldHashAlgo(accounts, network, oldHashAlgo);
}
if (issues.signer0?.length && issues.signer0?.length > 0) {
await fixSigner0(accounts, network, issues.signer0);
}
}
10 changes: 5 additions & 5 deletions issues/oldHashAlgo/fix.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { BigNumber } from "ethers";
import ora from "ora";
import { Account as SNAccount } from "starknet-390/dist/account";
import { Provider } from "starknet-390/dist/provider";
import ec from "starknet-390/dist/utils/ellipticCurve";
import stark from "starknet-390/dist/utils/stark";
import { ec, Provider, stark, Account as SNAccount } from "starknet-390";
import { oraLog } from "../../oraLog";
import { Account } from "../../ui/pickAccounts";

const LATEST_ACCOUNT_IMPLEMENTATION_ADDRESS =
"0x01bd7ca87f139693e6681be2042194cf631c4e8d77027bf0ea9e6d55fc6018ac";
"0x01bd7ca87f139693e6681be2042194cf631c4e8d77027bf0ea9e6d55fc6018ac"; // KEEP

export const fix = async (
accounts: Account[],
Expand Down Expand Up @@ -48,6 +45,9 @@ export const fix = async (
});
oraLog(spinner, `Transaction ${transaction.transaction_hash} created`);
await provider.waitForTransaction(transaction.transaction_hash);

// wait 1 minute extra to make sure the transaction is mined
await new Promise((resolve) => setTimeout(resolve, 60000));
}
}
spinner.succeed(`Fixed oldHashAlgo issue`);
Expand Down
8 changes: 8 additions & 0 deletions issues/signer0/detect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { BigNumber } from "ethers";
import { Account } from "../../ui/pickAccounts";

export const detect = async (accounts: Account[]): Promise<string[]> => {
return accounts
.filter(({ signer }) => BigNumber.from(signer).eq(0))
.map(({ address }) => address);
};
52 changes: 52 additions & 0 deletions issues/signer0/fix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import ora from "ora";
import { ec, SequencerProvider } from "starknet";
import { compileCalldata } from "starknet/dist/utils/stark";
import { execute } from "../../execute";
import { oraLog } from "../../oraLog";
import { Account, pickAccounts } from "../../ui/pickAccounts";

export const fix = async (
accounts: Account[],
network: "mainnet-alpha" | "goerli-alpha",
accountsToRecover: string[]
): Promise<void> => {
const [accountToCredit] = await pickAccounts(accounts, network, {
single: true,
accountsToRecoverMessage:
"Select the account you want to use for the recovery",
});
if (!accountToCredit) {
throw new Error("No account to credit");
}
const privateKey = accountToCredit.privateKey;
if (!privateKey) {
throw new Error("No private key for account to credit");
}
const spinner = ora(`Fixing 0signer issue (this may take some time)`).start();
const provider = new SequencerProvider({ network });
const keyPair = ec.getKeyPair(privateKey);
const starkKey = ec.getStarkKey(keyPair);

for (const address of accountsToRecover) {
const transaction = await execute(accountToCredit, {
contractAddress: address,
entrypoint: "initialize",
calldata: compileCalldata({
signer: starkKey,
guardian: "0",
}),
});
oraLog(spinner, `Transaction ${transaction.transaction_hash} created`);
await provider.waitForTransaction(transaction.transaction_hash);

const accountToUpdate = accounts.find((a) => a.address === address);
if (accountToUpdate) {
accountToUpdate.signer = starkKey;
accountToUpdate.privateKey = privateKey;
}

// wait 1 minute extra to make sure the transaction is mined
await new Promise((resolve) => setTimeout(resolve, 60000));
}
spinner.succeed(`Fixed 0signer issue`);
};
Loading

0 comments on commit 7542834

Please sign in to comment.