Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cairo 1 support #202

Merged
merged 34 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9fe75f1
feat: change account contract to cairo 1 (#152)
stanleyyconsensys Oct 4, 2023
1db6955
feat: sf-542 block cairo0 (#153)
stanleyyconsensys Oct 5, 2023
42a1f90
chore(deps): bump word-wrap from 1.2.3 to 1.2.5 (#131)
dependabot[bot] Oct 5, 2023
1a32b29
chore(deps): bump @adobe/css-tools from 4.2.0 to 4.3.1 (#132)
dependabot[bot] Oct 5, 2023
be880ca
chore(deps): bump semver from 7.3.8 to 7.5.2 (#130)
dependabot[bot] Oct 5, 2023
101804d
Merge branch 'main' into releases/2.3.0
stanleyyconsensys Oct 13, 2023
62f589e
feat: merge main
stanleyyconsensys Nov 17, 2023
2ee8e1b
feat: simplify snap logic
stanleyyconsensys Nov 17, 2023
ba81932
Merge branch 'main' into releases/2.3.0
stanleyyconsensys Nov 21, 2023
b87e23d
fix: replace hardcode class hash
stanleyyconsensys Nov 21, 2023
ef4eb37
fix: get version function
stanleyyconsensys Nov 21, 2023
bd45f53
fix: recover account for getting upgraded cairo 1 address
stanleyyconsensys Nov 21, 2023
c166dde
feat: sf 549 update all method to support upgraded address (#188)
stanleyyconsensys Jan 5, 2024
eb5f4d7
feat: sf-540 add account contract upgrade api (#189)
stanleyyconsensys Feb 21, 2024
34a11a4
Merge branch 'main' into releases/2.3.0
stanleyyconsensys Feb 28, 2024
c9270ac
feat: sf-539 UI upgrade account (#191)
stanleyyconsensys Feb 28, 2024
b0c4817
fix: test (#203)
stanleyyconsensys Feb 28, 2024
e84dd4e
Merge branch 'main' into releases/2.3.0
stanleyyconsensys Mar 22, 2024
c8276d0
chore: rebase
stanleyyconsensys Mar 22, 2024
065cc40
Merge branch 'main' into releases/2.3.0
stanleyyconsensys Apr 10, 2024
213b2e2
chore: update conflict
stanleyyconsensys Apr 10, 2024
63e405a
fix: lint issue
stanleyyconsensys Apr 11, 2024
29f7a29
feat: sf 614 rebase (#246)
stanleyyconsensys Jun 6, 2024
61d6a0f
Merge branch 'main' into releases/2.3.0
stanleyyconsensys Jun 12, 2024
2fedd78
chore: lint style
stanleyyconsensys Jun 12, 2024
b5cd8c6
fix: lint issue
stanleyyconsensys Jun 12, 2024
17f5975
fix: yarn lock
stanleyyconsensys Jun 12, 2024
fe5631d
Merge branch 'main' into releases/2.3.0
stanleyyconsensys Jun 12, 2024
3209fe3
chore: add update text
stanleyyconsensys Jun 13, 2024
d695ead
chore: update snap file
stanleyyconsensys Jun 13, 2024
47ffbb5
chore: update yarn.lock
stanleyyconsensys Jun 13, 2024
0af0afb
chore: update snap sdk
stanleyyconsensys Jun 18, 2024
20f4fac
chore: update snap sdk
stanleyyconsensys Jun 18, 2024
f77eb06
fix: building and unit tests
khanti42 Jun 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions packages/starknet-snap/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,15 @@ <h1>Hello, Snaps!</h1>
<input type="submit" id="estimateFees" value="Estimate Fees" />
</fieldset>
</form>
<form id="upgrade">
<fieldset>
<legend>Upgrade Cairo Version from 0 to 1</legend>
<label for="upgrade_contractAddress">Contract Address</label>
<input type="text" id="upgrade_contractAddress" name="upgrade_contractAddress" /><br />
<input type="submit" id="upgrade" value="Upgrade" />
</fieldset>
</form>

</body>

<script type="module">
Expand Down Expand Up @@ -479,6 +488,10 @@ <h1>Hello, Snaps!</h1>
id: 'estimateFees',
method: estimateFees,
},
{
id: 'upgrade',
method: upgrade,
},
];

for (const form of formWithSubmit) {
Expand Down Expand Up @@ -876,6 +889,16 @@ <h1>Hello, Snaps!</h1>
});
}

async function upgrade(e) {
e.preventDefault(); // to prevent default form behavior

const contractAddress = document.getElementById('upgrade_contractAddress').value;

await callSnap('starkNet_upgradeAccContract', {
contractAddress
});
}

async function callSnap(method, params) {
try {
const chainId = document.getElementById('targetChainId').value;
Expand All @@ -901,5 +924,8 @@ <h1>Hello, Snaps!</h1>
alert(`${method} problem happened: ${err.message || err}`);
}
}

</script>


</html>
43 changes: 43 additions & 0 deletions packages/starknet-snap/openrpc/starknet_snap_api_openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,49 @@
},
"errors": []
},
{
"name": "starkNet_upgradeAccContract",
"summary": "Upgrade Account Contract",
"paramStructure": "by-name",
"params": [
{
"name": "contractAddress",
"summary": "Address of the target contract",
"description": "Address of the target contract",
"required": true,
"schema": {
"$ref": "#/components/schemas/ADDRESS"
}
},
{
"name": "maxFee",
"summary": "Maximum gas fee allowed from the sender",
"description": "Maximum gas fee allowed from the sender (if not given, the max fee will be automatically calculated)",
"required": false,
"schema": {
"$ref": "#/components/schemas/NUM_AS_HEX"
}
},
{
"name": "chainId",
"summary": "Id of the target Starknet network",
"description": "Id of the target Starknet network (default to Starknet Goerli Testnet)",
"required": false,
"schema": {
"$ref": "#/components/schemas/CHAIN_ID"
}
}
],
"result": {
"name": "result",
"summary": "Response from Starknet’s \"gateway/call_contract\" endpoint",
"description": "Response from Starknet’s \"gateway/call_contract\" endpoint",
"schema": {
"$ref": "#/components/schemas/SEND_TRANSACTION_RESULT"
}
},
"errors": []
},
{
"name": "starkNet_getTransactionStatus",
"summary": "Gets the status of a transaction",
Expand Down
1 change: 1 addition & 0 deletions packages/starknet-snap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"lint:fix": "eslint '**/*.{js,ts,tsx}' --fix",
"test": "yarn run test:unit && yarn run cover:report",
"test:unit": "nyc --check-coverage --statements 80 --branches 80 --functions 80 --lines 80 mocha --colors -r ts-node/register \"test/**/*.test.ts\"",
"test:unit:one": "nyc --check-coverage --statements 80 --branches 80 --functions 80 --lines 80 mocha --colors -r ts-node/register",
"cover:report": "nyc report --reporter=lcov --reporter=text"
},
"keywords": [],
Expand Down
2 changes: 1 addition & 1 deletion packages/starknet-snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/ConsenSys/starknet-snap.git"
},
"source": {
"shasum": "n98JYVZFBDx4LYHqusYAftu/diScJU/ePb8FTYHZXsU=",
"shasum": "kl5iM2GRyXtFYwezb2vvrh2iTNC4Gw4K1I3PVOttXJ4=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
40 changes: 19 additions & 21 deletions packages/starknet-snap/src/createAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import {
getKeysFromAddressIndex,
getAccContractAddressAndCallData,
deployAccount,
callContract,
getBalance,
estimateAccountDeployFee,
getSigner,
isAccountDeployed,
waitForTransaction,
} from './utils/starknetUtils';
import {
Expand Down Expand Up @@ -53,8 +53,6 @@ export async function createAccount(params: ApiParams, silentMode = false, waitM

let failureReason = '';
let estimateDeployFee: EstimateFee;
let signerAssigned = true;
let signer = '';

if (deploy) {
if (!silentMode) {
Expand All @@ -80,24 +78,16 @@ export async function createAccount(params: ApiParams, silentMode = false, waitM
};
}

try {
signer = await getSigner(contractAddress, network);
logger.log(`createAccount:\ngetSigner: contractAddress = ${contractAddress}, signerPublicKey= ${signer}`);
failureReason = 'The account address had already been deployed';
} catch (err) {
signerAssigned = false;
logger.log(`createAccount:\ngetSigner: err in get signer: ${toJson(err)}`);
}
const signerAssigned = await isAccountDeployed(network, contractAddress);

if (!signerAssigned) {
try {
const getBalanceResp = await callContract(
network,
const balance = await getBalance(
getEtherErc20Token(state, network.chainId)?.address,
'balanceOf',
[num.toBigInt(contractAddress).toString(10)],
num.toBigInt(contractAddress).toString(10),
network,
);
logger.log(`createAccount:\ngetBalanceResp: ${toJson(getBalanceResp)}`);
logger.log(`createAccount:\ngetBalanceResp: ${balance}`);
estimateDeployFee = await estimateAccountDeployFee(
network,
contractAddress,
Expand All @@ -106,7 +96,7 @@ export async function createAccount(params: ApiParams, silentMode = false, waitM
privateKey,
);
logger.log(`createAccount:\nestimateDeployFee: ${toJson(estimateDeployFee)}`);
if (Number(getBalanceResp[0]) < Number(estimateDeployFee.suggestedMaxFee)) {
if (Number(balance) < Number(estimateDeployFee.suggestedMaxFee)) {
const gasFeeStr = ethers.utils.formatUnits(estimateDeployFee.suggestedMaxFee.toString(10), 18);
const gasFeeFloat = parseFloat(gasFeeStr).toFixed(6); // 6 decimal places for ether
const gasFeeInEther = Number(gasFeeFloat) === 0 ? '0.000001' : gasFeeFloat;
Expand All @@ -118,9 +108,17 @@ export async function createAccount(params: ApiParams, silentMode = false, waitM
}
}

const deployResp = await deployAccount(network, contractAddress, contractCallData, publicKey, privateKey, {
maxFee: estimateDeployFee?.suggestedMaxFee,
});
const deployResp = await deployAccount(
network,
contractAddress,
contractCallData,
publicKey,
privateKey,
undefined,
{
maxFee: estimateDeployFee?.suggestedMaxFee,
},
);

if (deployResp.contract_address && deployResp.transaction_hash) {
const userAccount: AccContract = {
Expand Down
32 changes: 18 additions & 14 deletions packages/starknet-snap/src/estimateFee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@ import {
estimateFeeBulk,
addFeesFromAllTransactions,
isAccountDeployed,
isUpgradeRequired,
} from './utils/starknetUtils';

import { PROXY_CONTRACT_HASH } from './utils/constants';
import { ACCOUNT_CLASS_HASH } from './utils/constants';
import { logger } from './utils/logger';

export async function estimateFee(params: ApiParams) {
try {
const { state, keyDeriver, requestParams } = params;
const requestParamsObj = requestParams as EstimateFeeRequestParams;
const contractAddress = requestParamsObj.contractAddress;
const contractFuncName = requestParamsObj.contractFuncName;
const contractCallData = getCallDataArray(requestParamsObj.contractCallData);
const senderAddress = requestParamsObj.senderAddress;
const network = getNetworkFromChainId(state, requestParamsObj.chainId);

if (!requestParamsObj.contractAddress || !requestParamsObj.senderAddress || !requestParamsObj.contractFuncName) {
if (!contractAddress || !requestParamsObj.senderAddress || !contractFuncName) {
throw new Error(
`The given contract address, sender address, and function name need to be non-empty string, got: ${toJson(
requestParamsObj,
Expand All @@ -30,21 +35,20 @@ export async function estimateFee(params: ApiParams) {
}

try {
validateAndParseAddress(requestParamsObj.contractAddress);
validateAndParseAddress(contractAddress);
} catch (err) {
throw new Error(`The given contract address is invalid: ${requestParamsObj.contractAddress}`);
throw new Error(`The given contract address is invalid: ${contractAddress}`);
}
try {
validateAndParseAddress(requestParamsObj.senderAddress);
validateAndParseAddress(senderAddress);
} catch (err) {
throw new Error(`The given sender address is invalid: ${requestParamsObj.senderAddress}`);
throw new Error(`The given sender address is invalid: ${senderAddress}`);
}

if (await isUpgradeRequired(network, senderAddress)) {
throw new Error('Upgrade required');
}

const contractAddress = requestParamsObj.contractAddress;
const contractFuncName = requestParamsObj.contractFuncName;
const contractCallData = getCallDataArray(requestParamsObj.contractCallData);
const senderAddress = requestParamsObj.senderAddress;
const network = getNetworkFromChainId(state, requestParamsObj.chainId);
const { privateKey: senderPrivateKey, publicKey } = await getKeysFromAddress(
keyDeriver,
network,
Expand All @@ -61,7 +65,7 @@ export async function estimateFee(params: ApiParams) {
logger.log(`estimateFee:\ntxnInvocation: ${toJson(txnInvocation)}`);

//Estimate deploy account fee if the signer has not been deployed yet
const accountDeployed = await isAccountDeployed(network, publicKey);
const accountDeployed = await isAccountDeployed(network, senderAddress);
let bulkTransactions: Invocations = [
{
type: TransactionType.INVOKE,
Expand All @@ -71,7 +75,7 @@ export async function estimateFee(params: ApiParams) {
if (!accountDeployed) {
const { callData } = getAccContractAddressAndCallData(publicKey);
const deployAccountpayload = {
classHash: PROXY_CONTRACT_HASH,
classHash: ACCOUNT_CLASS_HASH,
contractAddress: senderAddress,
constructorCalldata: callData,
addressSalt: publicKey,
Expand Down
2 changes: 1 addition & 1 deletion packages/starknet-snap/src/estimateFees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function estimateFees(params: ApiParams) {
senderAddress,
senderPrivateKey,
requestParamsObj.invocations,
requestParamsObj.invocationDetails ? requestParamsObj.invocationDetails : undefined,
requestParamsObj.invocationDetails,
);

return fees.map((fee) => ({
Expand Down
21 changes: 11 additions & 10 deletions packages/starknet-snap/src/extractPrivateKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { toJson } from './utils/serializer';
import { validateAndParseAddress } from '../src/utils/starknetUtils';
import { ApiParams, ExtractPrivateKeyRequestParams } from './types/snapApi';
import { getNetworkFromChainId } from './utils/snapUtils';
import { getKeysFromAddress } from './utils/starknetUtils';
import { getKeysFromAddress, isUpgradeRequired } from './utils/starknetUtils';
import { DialogType } from '@metamask/rpc-methods';
import { copyable, panel, text } from '@metamask/snaps-sdk';
import { logger } from './utils/logger';
Expand All @@ -11,17 +11,20 @@ export async function extractPrivateKey(params: ApiParams) {
try {
const { state, wallet, keyDeriver, requestParams } = params;
const requestParamsObj = requestParams as ExtractPrivateKeyRequestParams;

if (!requestParamsObj.userAddress) {
throw new Error(
`The given user address need to be non-empty string, got: ${toJson(requestParamsObj.userAddress)}`,
);
const network = getNetworkFromChainId(state, requestParamsObj.chainId);
const userAddress = requestParamsObj.userAddress;
if (!userAddress) {
throw new Error(`The given user address need to be non-empty string, got: ${toJson(userAddress)}`);
}

try {
validateAndParseAddress(requestParamsObj.userAddress);
validateAndParseAddress(userAddress);
} catch (err) {
throw new Error(`The given user address is invalid: ${requestParamsObj.userAddress}`);
throw new Error(`The given user address is invalid: ${userAddress}`);
}

if (await isUpgradeRequired(network, userAddress)) {
throw new Error('Upgrade required');
}

const response = await wallet.request({
Expand All @@ -33,8 +36,6 @@ export async function extractPrivateKey(params: ApiParams) {
});

if (response === true) {
const userAddress = requestParamsObj.userAddress;
const network = getNetworkFromChainId(state, requestParamsObj.chainId);
const { privateKey: userPrivateKey } = await getKeysFromAddress(keyDeriver, network, state, userAddress);

await wallet.request({
Expand Down
6 changes: 5 additions & 1 deletion packages/starknet-snap/src/extractPublicKey.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toJson } from './utils/serializer';
import { constants, num } from 'starknet';
import { validateAndParseAddress } from '../src/utils/starknetUtils';
import { validateAndParseAddress, isUpgradeRequired } from '../src/utils/starknetUtils';
import { ApiParams, ExtractPublicKeyRequestParams } from './types/snapApi';
import { getAccount, getNetworkFromChainId } from './utils/snapUtils';
import { getKeysFromAddress } from './utils/starknetUtils';
Expand All @@ -26,6 +26,10 @@ export async function extractPublicKey(params: ApiParams) {
throw new Error(`The given user address is invalid: ${requestParamsObj.userAddress}`);
}

if (await isUpgradeRequired(network, userAddress)) {
throw new Error('Upgrade required');
}

let userPublicKey;
const accContract = getAccount(state, userAddress, network.chainId);
if (!accContract?.publicKey || num.toBigInt(accContract.publicKey) === constants.ZERO) {
Expand Down
7 changes: 6 additions & 1 deletion packages/starknet-snap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { estimateFees } from './estimateFees';
import { declareContract } from './declareContract';
import { signDeclareTransaction } from './signDeclareTransaction';
import { signDeployAccountTransaction } from './signDeployAccountTransaction';
import { upgradeAccContract } from './upgradeAccContract';
import { logger } from './utils/logger';
import { getStarkName } from './getStarkName';

Expand Down Expand Up @@ -211,6 +212,10 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ origin, request }) =>
apiParams.keyDeriver = await getAddressKeyDeriver(snap);
return await estimateFees(apiParams);

case 'starkNet_upgradeAccContract':
apiParams.keyDeriver = await getAddressKeyDeriver(snap);
return upgradeAccContract(apiParams);

case 'starkNet_declareContract':
apiParams.keyDeriver = await getAddressKeyDeriver(snap);
return await declareContract(apiParams);
Expand Down Expand Up @@ -248,7 +253,7 @@ export const onInstall: OnInstallHandler = async () => {
export const onUpdate: OnUpdateHandler = async () => {
const component = panel([
text('Features released with this update:'),
text('Deprecation of the Starknet Goerli Testnet'),
text('Cairo contract upgrade support.'),
]);

await snap.request({
Expand Down
Loading
Loading