Skip to content
This repository was archived by the owner on Feb 11, 2025. It is now read-only.

Commit fa02b46

Browse files
authored
Merge pull request #14 from simonheys/fix/broken-transfer
fix(recover): update snjs, rpc and add basic cairo 1 recovery
2 parents fcfe8fa + 740d984 commit fa02b46

20 files changed

+2759
-111
lines changed

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
20.11.1

.vscode/launch.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"runtimeExecutable": "yarn",
11+
"runtimeArgs": ["ts-node", "index.ts"],
12+
"name": "Launch Program",
13+
"skipFiles": ["<node_internals>/**"],
14+
"console": "integratedTerminal"
15+
}
16+
]
17+
}

Readme.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ You can then choose to fix issues and recover your funds to a new account addres
99
It is simplest to download the latest release from the [releases page](https://github.com/argentlabs/argent-starknet-recover/releases).
1010
After downloading the binary matching your machine you can run it inside a terminal.
1111

12-
If you have Node installed you can also clone this repo and run `yarn && yarn start` to run the CLI tool.
12+
If you have `node`, `nvm` and `yarn` installed you can also clone this repo and run the following:
1313

14-
**Use at your own risks**
14+
```bash
15+
$ nvm use
16+
$ yarn
17+
$ yarn start
18+
```
19+
20+
**Use at your own risk**
21+
22+
## Debugging with VSCode
23+
24+
You can use the Run and Debug feature to debug with VSCode - good luck!

actions/transferAll/core.ts

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { BigNumber, utils } from "ethers";
2-
import { number, uint256 } from "starknet";
3-
import { compileCalldata } from "starknet/dist/utils/stark";
1+
import { utils } from "ethers";
2+
import { num, CallData } from "starknet";
3+
import { number, uint256 } from "starknet-410";
44
import { Account } from "../../ui/pickAccounts";
55
import TOKENS from "../../default-tokens.json";
66
import { Ora } from "ora";
@@ -22,24 +22,20 @@ export async function transferAll(acc: Account, newAddress: string, ora: Ora) {
2222
return {
2323
contractAddress: token,
2424
entrypoint: "transfer",
25-
calldata: compileCalldata({
25+
calldata: CallData.compile({
2626
to: newAddress.toLowerCase(),
27-
value: {
28-
type: "struct",
29-
...uint256.bnToUint256(
30-
number.toBN(
31-
utils
32-
.parseUnits(balance, tokenDetails?.decimals || 18)
33-
.toString()
34-
)
35-
),
36-
},
27+
value: uint256.bnToUint256(
28+
number.toBN(
29+
utils.parseUnits(balance, tokenDetails?.decimals || 18).toString()
30+
)
31+
),
3732
}),
3833
};
3934
});
4035

4136
if (calls.length) {
42-
const { suggestedMaxFee } = await estimateFee(acc, calls);
37+
const result = await estimateFee(acc, calls);
38+
const suggestedMaxFee = result.suggestedMaxFee || result.overall_fee;
4339

4440
const callsWithFee = calls
4541
.map((c) => {
@@ -48,7 +44,7 @@ export async function transferAll(acc: Account, newAddress: string, ora: Ora) {
4844
const balance = acc.balances[c.contractAddress];
4945
const amount = utils
5046
.parseUnits(balance, tokenDetails?.decimals ?? 18)
51-
.sub(number.toHex(suggestedMaxFee));
47+
.sub(num.toHex(suggestedMaxFee));
5248

5349
if (amount.lte(0)) {
5450
ora.info(
@@ -61,12 +57,9 @@ export async function transferAll(acc: Account, newAddress: string, ora: Ora) {
6157

6258
return {
6359
...c,
64-
calldata: compileCalldata({
60+
calldata: CallData.compile({
6561
to: newAddress.toLowerCase(),
66-
value: {
67-
type: "struct",
68-
...uint256.bnToUint256(number.toBN(amount.toString())),
69-
},
62+
value: uint256.bnToUint256(number.toBN(amount.toString())),
7063
}),
7164
};
7265
}

addressFormatting.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { encode } from "starknet";
1+
import { encode } from "starknet-410";
22

33
export const formatAddress = (address: string) =>
44
encode.addHexPrefix(encode.removeHexPrefix(address).padStart(64, "0"));

argent-x-multicall-4.8.7.tgz

-4.98 KB
Binary file not shown.

execute.ts

Lines changed: 92 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
import {
2-
RpcProvider as NewRpcProvider,
3-
Account as NewAccount,
4-
} from "starknet-4220";
1+
import { Account as LatestAccount } from "starknet";
2+
import { Account as Account4220 } from "starknet-4220";
53
import {
64
Call,
75
RpcProvider as OldRpcProvider,
86
Account as OldAccount,
97
ec,
10-
} from "starknet";
8+
} from "starknet-410";
119
import { BigNumber } from "ethers";
1210
import { Account } from "./ui/pickAccounts";
1311
import { lte } from "semver";
14-
import { getRpcNodeUrlForNetworkId } from "./getProvider";
12+
import {
13+
getProvider4220ForNetworkId,
14+
getProviderForNetworkId,
15+
getRpcNodeUrlForNetworkId,
16+
} from "./getProvider";
1517

1618
export async function estimateFee(account: Account, call: Call[] | Call) {
1719
const calls = Array.isArray(call) ? call : [call];
@@ -24,15 +26,43 @@ export async function estimateFee(account: Account, call: Call[] | Call) {
2426
);
2527
}
2628
const nodeUrl = getRpcNodeUrlForNetworkId(account.networkId);
29+
2730
try {
28-
const oldRpcProvider = new OldRpcProvider({ nodeUrl });
29-
const a = new OldAccount(oldRpcProvider, lowerCaseAddress, keyPair);
31+
if (!account.privateKey) {
32+
throw new Error("Account private key is missing");
33+
}
34+
const provider = getProviderForNetworkId(account.networkId);
35+
const a = new LatestAccount(provider, lowerCaseAddress, account.privateKey);
3036
return await a.estimateFee(calls);
31-
} catch {
32-
const newRpcProvider = new NewRpcProvider({ nodeUrl });
33-
const a = new NewAccount(newRpcProvider, lowerCaseAddress, keyPair);
37+
} catch (e) {
38+
console.warn(
39+
`Fallback to old provider - estimateFee error ${e}`,
40+
(e as any)?.errorCode
41+
);
42+
}
43+
44+
try {
45+
const provider = getProvider4220ForNetworkId(account.networkId);
46+
const a = new Account4220(provider, lowerCaseAddress, keyPair);
3447
return a.estimateFee(calls);
48+
} catch (e) {
49+
console.warn(
50+
`Fallback to old provider - estimateFee error ${e}`,
51+
(e as any)?.errorCode
52+
);
53+
}
54+
55+
try {
56+
const provider = new OldRpcProvider({ nodeUrl });
57+
const a = new OldAccount(provider, lowerCaseAddress, keyPair);
58+
return await a.estimateFee(calls);
59+
} catch (e) {
60+
console.warn(
61+
`Oldest provider failed - estimateFee error ${e}`,
62+
(e as any)?.errorCode
63+
);
3564
}
65+
throw new Error("Estimate fee failed");
3666
}
3767

3868
export async function execute(account: Account, call: Call[] | Call) {
@@ -45,28 +75,69 @@ export async function execute(account: Account, call: Call[] | Call) {
4575
"Account cant be controlled with the selected private key or seed"
4676
);
4777
}
78+
4879
const nodeUrl = getRpcNodeUrlForNetworkId(account.networkId);
4980
if (account.version && lte(account.version, "0.2.2")) {
5081
try {
51-
const oldRpcProvider = new OldRpcProvider({ nodeUrl });
52-
const a = new OldAccount(oldRpcProvider, lowerCaseAddress, keyPair);
82+
const provider = new OldRpcProvider({ nodeUrl });
83+
const a = new OldAccount(provider, lowerCaseAddress, keyPair);
5384
return await a.execute(calls);
5485
} catch (e) {
55-
console.warn("Fallback to new provider", (e as any)?.errorCode);
56-
const newRpcProvider = new NewRpcProvider({ nodeUrl });
57-
const a = new NewAccount(newRpcProvider, lowerCaseAddress, keyPair);
86+
console.warn(
87+
`Fallback to old provider - estimateFee error ${e}`,
88+
(e as any)?.errorCode
89+
);
90+
}
91+
try {
92+
const provider = getProvider4220ForNetworkId(account.networkId);
93+
const a = new Account4220(provider, lowerCaseAddress, keyPair);
5894
return await a.execute(calls);
95+
} catch (e) {
96+
console.warn(
97+
`Oldest provider failed - execute error ${e}`,
98+
(e as any)?.errorCode
99+
);
59100
}
60101
} else {
61102
try {
62-
const newRpcProvider = new NewRpcProvider({ nodeUrl });
63-
const a = new NewAccount(newRpcProvider, lowerCaseAddress, keyPair);
103+
if (!account.privateKey) {
104+
throw new Error("Account private key is missing");
105+
}
106+
const provider = getProviderForNetworkId(account.networkId);
107+
const a = new LatestAccount(
108+
provider,
109+
lowerCaseAddress,
110+
account.privateKey
111+
);
64112
return await a.execute(calls);
65113
} catch (e) {
66-
console.warn("Fallback to old provider", (e as any)?.errorCode);
67-
const oldRpcProvider = new OldRpcProvider({ nodeUrl });
68-
const a = new OldAccount(oldRpcProvider, lowerCaseAddress, keyPair);
114+
console.warn(
115+
`Fallback to older provider - execute error ${e}`,
116+
(e as any)?.errorCode
117+
);
118+
}
119+
120+
try {
121+
const provider = getProvider4220ForNetworkId(account.networkId);
122+
const a = new Account4220(provider, lowerCaseAddress, keyPair);
69123
return await a.execute(calls);
124+
} catch (e) {
125+
console.warn(
126+
`Fallback to older provider - execute error ${e}`,
127+
(e as any)?.errorCode
128+
);
129+
}
130+
131+
try {
132+
const provider = new OldRpcProvider({ nodeUrl });
133+
const a = new OldAccount(provider, lowerCaseAddress, keyPair);
134+
return await a.execute(calls);
135+
} catch (e) {
136+
console.warn(
137+
`Oldest provider failed - execute error ${e}`,
138+
(e as any)?.errorCode
139+
);
70140
}
71141
}
142+
throw new Error("Execute transation failed");
72143
}

genSigners.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BigNumber, Wallet } from "ethers";
2-
import { ec, number } from "starknet";
2+
import { ec, number } from "starknet-410";
33
import { BASE_DERIVATION_PATHS } from "./getAccounts";
44
import { getPathForIndex, getStarkPair } from "./keyDerivation";
55

getAccounts.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Wallet } from "ethers";
2-
import { ec, hash, number, stark } from "starknet";
2+
import { ec, hash, number, stark } from "starknet-410";
33
import { getBalances } from "./getTokenBalance";
44
import { getPathForIndex, getStarkPair } from "./keyDerivation";
5-
import { getProviderForNetworkId } from "./getProvider";
5+
import { getProvider4220ForNetworkId } from "./getProvider";
66
import { NetworkId } from "./types";
77

88
const CHECK_OFFSET = 10;
@@ -17,6 +17,12 @@ const ARGENT_ACCOUNT_CONTRACT_CLASS_HASHES = [
1717
"0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2",
1818
];
1919

20+
const ARGENT_ACCOUNT_CONTRACT_CLASS_HASHES_CAIRO_1 = [
21+
"0x29927c8af6bccf3f6fda035981e765a7bdbf18a2dc0d630494f8758aa908e2b",
22+
"0x02fadbf77a721b94bdcc3032d86a8921661717fa55145bccf88160ee2a5efcd1",
23+
"0x1a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003",
24+
];
25+
2026
export const BASE_DERIVATION_PATHS = [
2127
"m/44'/9004'/0'/0",
2228
"m/2645'/1195502025'/1148870696'/0'/0'",
@@ -28,7 +34,7 @@ async function getAccountByKeyPair(
2834
contractClassHash: string,
2935
accountClassHash: string
3036
) {
31-
const provider = getProviderForNetworkId(networkId);
37+
const provider4220 = getProvider4220ForNetworkId(networkId);
3238

3339
const starkPub = ec.getStarkKey(keyPair);
3440

@@ -58,7 +64,7 @@ async function getAccountByKeyPair(
5864
};
5965
}
6066

61-
const code = await provider.getCode(address);
67+
const code = await provider4220.getCode(address);
6268

6369
if (code.bytecode.length > 0) {
6470
return {
@@ -90,6 +96,16 @@ export async function getAccountsBySeedPhrase(
9096
)
9197
);
9298

99+
BASE_DERIVATION_PATHS.forEach((dp) => {
100+
ARGENT_ACCOUNT_CONTRACT_CLASS_HASHES_CAIRO_1.forEach((accountClassHash) => {
101+
proxyClassHashAndAccountClassHash2DMap.push([
102+
accountClassHash,
103+
accountClassHash,
104+
dp,
105+
]);
106+
});
107+
});
108+
93109
const accounts: {
94110
address: string;
95111
deployImplementation?: string;

getImplementation.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
1-
import { Multicall } from "@argent/x-multicall";
2-
import { getProviderForNetworkId } from "./getProvider";
1+
import {
2+
getProviderForNetworkId,
3+
getRpcBatchProviderForNetworkId,
4+
} from "./getProvider";
35
import { NetworkId } from "./types";
46

57
export async function getImplementation(
68
addresses: string[],
79
networkId: NetworkId
810
) {
9-
const provider = getProviderForNetworkId(networkId);
10-
const multicallProvider = new Multicall(provider as any);
11+
const multicall = getRpcBatchProviderForNetworkId(networkId);
1112

1213
const implementationAnswers = await Promise.allSettled(
13-
addresses.map((address) =>
14-
multicallProvider.call({
14+
addresses.map(async (address) => {
15+
const get_implementation = await multicall.callContract({
1516
contractAddress: address,
1617
entrypoint: "get_implementation",
17-
})
18-
)
18+
});
19+
if (get_implementation !== undefined) {
20+
return get_implementation;
21+
}
22+
try {
23+
const provider = getProviderForNetworkId(networkId);
24+
const classHash = await provider.getClassHashAt(address);
25+
return classHash;
26+
} catch (e) {
27+
console.warn("Assuming tx V1 implementation");
28+
const TXV1_ACCOUNT_CLASS_HASH =
29+
"0x1a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003";
30+
return TXV1_ACCOUNT_CLASS_HASH;
31+
}
32+
})
1933
);
2034

2135
const implementations = implementationAnswers

0 commit comments

Comments
 (0)