Skip to content

Commit

Permalink
fix: 429 error
Browse files Browse the repository at this point in the history
  • Loading branch information
janek26 committed Apr 3, 2023
1 parent a6de240 commit 585a386
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 58 deletions.
68 changes: 35 additions & 33 deletions actions/transferAll/core.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import { BigNumber, utils } from "ethers";
import {
Account as SNAccount,
ec,
number,
SequencerProvider,
uint256,
} from "starknet";
import { number, uint256 } from "starknet";
import { compileCalldata } from "starknet/dist/utils/stark";
import { Account } from "../../ui/pickAccounts";
import TOKENS from "../../default-tokens.json";
import { Ora } from "ora";
import { oraLog } from "../../oraLog";
import { estimateFee, execute } from "../../execute";
import { formatAddress } from "../../addressFormatting";

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 provider = new SequencerProvider({ network: acc.networkId as any });
const tokens = TOKENS.filter((t) => t.network === acc.networkId);
const calls = Object.entries(acc.balances)
.filter(([, balance]) => utils.parseEther(balance).gt(0))
Expand Down Expand Up @@ -47,36 +41,44 @@ export async function transferAll(acc: Account, newAddress: string, ora: Ora) {
if (calls.length) {
const { suggestedMaxFee } = await estimateFee(acc, calls);

const callsWithFee = calls.map((c) => {
const tokenDetails = tokens.find((t) => t.symbol === "ETH");
if (c.contractAddress === tokenDetails?.address) {
const balance = acc.balances[c.contractAddress];
return {
...c,
calldata: compileCalldata({
to: newAddress.toLowerCase(),
value: {
type: "struct",
...uint256.bnToUint256(
number.toBN(
utils
.parseUnits(balance, tokenDetails?.decimals ?? 18)
.sub(number.toHex(suggestedMaxFee))
.toString()
)
),
},
}),
};
}
return c;
});
const callsWithFee = calls
.map((c) => {
const tokenDetails = tokens.find((t) => t.symbol === "ETH");
if (c.contractAddress === tokenDetails?.address) {
const balance = acc.balances[c.contractAddress];
const amount = utils
.parseUnits(balance, tokenDetails?.decimals ?? 18)
.sub(number.toHex(suggestedMaxFee));

if (amount.lte(0)) {
ora.info(
`Account ${formatAddress(
acc.address
)} has not enough ETH to do a transfer`
);
return false;
}

return {
...c,
calldata: compileCalldata({
to: newAddress.toLowerCase(),
value: {
type: "struct",
...uint256.bnToUint256(number.toBN(amount.toString())),
},
}),
};
}
return c;
})
.filter(Boolean);

// execute with suggested max fee substracted from a potential eth transfer
const transaction = await execute(acc, callsWithFee);

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

await provider.waitForTransaction(transaction.transaction_hash);
return transaction.transaction_hash;
}
}
52 changes: 46 additions & 6 deletions actions/transferAll/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@ import { ValidationError } from "yup";
import { addressSchema } from "../../schema";
import { Account } from "../../ui/pickAccounts";
import { transferAll } from "./core";
import { SequencerProvider } from "starknet-4220";

type PromiseFactory<T> = () => Promise<T>;

type PromiseResult<T> =
| { status: "fulfilled"; value: T }
| { status: "rejected"; reason: any };

async function allSettled<T>(
promiseFactories: PromiseFactory<T>[]
): Promise<PromiseResult<T>[]> {
const results: PromiseResult<T>[] = [];

for (const promiseFactory of promiseFactories) {
try {
const value = await promiseFactory();
results.push({ status: "fulfilled", value });
} catch (reason) {
results.push({ status: "rejected", reason });
}
}

return results;
}

export async function showTransferAll(accounts: Account[]) {
const { toAddress } = await prompts(
Expand All @@ -30,16 +54,32 @@ export async function showTransferAll(accounts: Account[]) {

const spinner = ora("Transfering tokens").start();

const transferResults = await Promise.allSettled(
accounts.map(async (acc) => transferAll(acc, toAddress, spinner))
const transferResults = await allSettled(
accounts.map((acc) => () => transferAll(acc, toAddress, spinner))
);

transferResults.forEach((result) => {
if (result.status === "rejected") {
spinner.fail(result.reason?.toString());
}
const transactions = transferResults
.map((result) => {
if (result.status === "rejected") {
spinner.fail(result.reason?.toString());
return undefined;
}
return result.value;
})
.filter((tx) => !!tx);

const provider = new SequencerProvider({
network: accounts[0].networkId as any,
});

spinner.info(`Waiting for ${transactions.length} transactions`);
await Promise.all(
transactions.map((tx) => {
if (!tx) return;
return provider.waitForTransaction(tx);
})
);

if (transferResults.every((result) => result.status === "fulfilled")) {
spinner.succeed("Transfers complete");
} else if (transferResults.some((result) => result.status === "fulfilled")) {
Expand Down
43 changes: 32 additions & 11 deletions execute.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
SequencerProvider as NewProvider,
Account as NewAccount,
} from "starknet-490";
} from "starknet-4220";
import {
Call,
SequencerProvider as OldProvider,
Expand All @@ -10,6 +10,7 @@ import {
} from "starknet";
import { BigNumber } from "ethers";
import { Account } from "./ui/pickAccounts";
import { lte } from "semver";

export async function estimateFee(account: Account, call: Call[] | Call) {
const calls = Array.isArray(call) ? call : [call];
Expand Down Expand Up @@ -42,15 +43,35 @@ export async function execute(account: Account, call: Call[] | Call) {
"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) {
const newProvider = new NewProvider({ network: account.networkId as any });
const a = new NewAccount(newProvider, lowerCaseAddress, keyPair);
return a.execute(calls).catch((e) => {
throw e;
});
if (account.version && lte(account.version, "0.2.2")) {
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("Fallback to new provider", (e as any)?.errorCode);
const newProvider = new NewProvider({
network: account.networkId as any,
});
const a = new NewAccount(newProvider, lowerCaseAddress, keyPair);
return await a.execute(calls);
}
} else {
try {
const newProvider = new NewProvider({
network: account.networkId as any,
});
const a = new NewAccount(newProvider, lowerCaseAddress, keyPair);
return await a.execute(calls);
} catch (e) {
console.warn("Fallback to old provider", (e as any)?.errorCode);
const oldProvider = new OldProvider({
network: account.networkId as any,
});
const a = new OldAccount(oldProvider, lowerCaseAddress, keyPair);
return await a.execute(calls);
}
}
}
23 changes: 23 additions & 0 deletions fetchPolyfill.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import ora from "ora";

type Fetch = typeof fetch;

const originalFetch: Fetch = fetch.bind(globalThis);

const wait = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));

const customFetch: Fetch = async (input, init): Promise<Response> => {
const response = await originalFetch(input, init);

if (response.status === 429) {
// Wait for one minute before retrying
ora().warn("429 - waiting 1 minute before retrying request");
await wait(60 * 1000);
return originalFetch(input, init);
}

return response;
};

globalThis.fetch = customFetch;
3 changes: 3 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/env npx ts-node
import "@total-typescript/ts-reset";
import "./fetchPolyfill";

import { program } from "commander";
import ora from "ora";
import { Account, pickAccounts } from "./ui/pickAccounts";
Expand Down
2 changes: 1 addition & 1 deletion issues/deploy/fix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
SequencerProvider,
stark,
hash,
} from "starknet-490";
} from "starknet-4220";
import { PROXY_CONTRACT_CLASS_HASHES } from "../../getAccounts";
import { getVersion } from "../../getVersion";
import { oraLog } from "../../oraLog";
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"outputPath": "bin"
},
"devDependencies": {
"@total-typescript/ts-reset": "^0.4.2",
"@types/lodash.chunk": "^4.2.7",
"@types/prompts": "^2.0.14",
"@types/semver": "^7.3.10",
Expand All @@ -40,9 +41,9 @@
"ora": "5",
"prompts": "^2.4.2",
"semver": "^7.3.7",
"starknet-490": "npm:starknet@4.9.0",
"starknet": "4.1.0",
"starknet-390": "npm:starknet@3.9.0",
"starknet-4220": "npm:starknet@4.22.0",
"yup": "^1.0.0-beta.4"
}
}
34 changes: 28 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,11 @@
"@noble/hashes" "~1.1.1"
"@scure/base" "~1.1.0"

"@total-typescript/ts-reset@^0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@total-typescript/ts-reset/-/ts-reset-0.4.2.tgz#c564c173ba09973968e1046c93965b7a257878a4"
integrity sha512-vqd7ZUDSrXFVT1n8b2kc3LnklncDQFPvR58yUS1kEP23/nHPAO9l1lMjUfnPrXYYk4Hj54rrLKMW5ipwk7k09A==

"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
Expand Down Expand Up @@ -1905,10 +1910,10 @@ slash@^3.0.0:
superstruct "^0.15.3"
url-join "^4.0.1"

"starknet-490@npm:starknet@4.9.0", starknet@^4.9.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/starknet/-/starknet-4.9.0.tgz#1d0b5a1ff532a41b84a619f3d7c3f833f67dad2d"
integrity sha512-0Y9Nce0msMs1k3jid93ZuPD2e3yW42FUuMFChRTaq1qcjP8G/fL+5+/zuq441VQ82/JxAHnVqBMvpmMgn5yJSA==
"starknet-4220@npm:starknet@4.22.0":
version "4.22.0"
resolved "https://registry.yarnpkg.com/starknet/-/starknet-4.22.0.tgz#8d0c628e2a8e868ee9b4757afe89f07b05ec55ff"
integrity sha512-jC9Taxb6a/ht9zmS1LU/DSLfwJKpgCJnE9AktVksc5SE/+jQMpqxsq6fm7PRiqupjiqRC1DOS8N47cj+KaGv4Q==
dependencies:
"@ethersproject/bytes" "^5.6.1"
bn.js "^5.2.1"
Expand All @@ -1919,7 +1924,7 @@ slash@^3.0.0:
json-bigint "^1.0.0"
minimalistic-assert "^1.0.1"
pako "^2.0.4"
ts-custom-error "^3.2.0"
ts-custom-error "^3.3.1"
url-join "^4.0.1"

starknet@4.1.0:
Expand All @@ -1939,6 +1944,23 @@ starknet@4.1.0:
ts-custom-error "^3.2.0"
url-join "^4.0.1"

starknet@^4.9.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/starknet/-/starknet-4.9.0.tgz#1d0b5a1ff532a41b84a619f3d7c3f833f67dad2d"
integrity sha512-0Y9Nce0msMs1k3jid93ZuPD2e3yW42FUuMFChRTaq1qcjP8G/fL+5+/zuq441VQ82/JxAHnVqBMvpmMgn5yJSA==
dependencies:
"@ethersproject/bytes" "^5.6.1"
bn.js "^5.2.1"
elliptic "^6.5.4"
ethereum-cryptography "^1.0.3"
hash.js "^1.1.7"
isomorphic-fetch "^3.0.0"
json-bigint "^1.0.0"
minimalistic-assert "^1.0.1"
pako "^2.0.4"
ts-custom-error "^3.2.0"
url-join "^4.0.1"

stream-meter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/stream-meter/-/stream-meter-1.0.4.tgz#52af95aa5ea760a2491716704dbff90f73afdd1d"
Expand Down Expand Up @@ -2069,7 +2091,7 @@ tr46@~0.0.3:
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==

ts-custom-error@^3.2.0:
ts-custom-error@^3.2.0, ts-custom-error@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/ts-custom-error/-/ts-custom-error-3.3.1.tgz#8bd3c8fc6b8dc8e1cb329267c45200f1e17a65d1"
integrity sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==
Expand Down

0 comments on commit 585a386

Please sign in to comment.