Skip to content

Commit

Permalink
⬆️ Upgrading dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
florian-bellotti committed Dec 10, 2024
1 parent 28924ab commit 0598877
Show file tree
Hide file tree
Showing 11 changed files with 11,186 additions and 1,056 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ yarn-error.log*
.DS_Store
Thumbs.db
api-doc.json
example/build
42 changes: 20 additions & 22 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,31 @@
},
"dependencies": {
"@avnu/gasless-sdk": "file:../dist",
"@starknet-react/chains": "0.1.7",
"@starknet-react/core": "2.8.0",
"ethers": "6.12.1",
"get-starknet-core": "3.3.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"starknet": "6.8.0"
"ethers": "6.13.4",
"get-starknet": "3.3.3",
"react": "19.0.0",
"react-dom": "19.0.0",
"starknet": "6.11.0"
},
"devDependencies": {
"@testing-library/jest-dom": "6.4.2",
"@testing-library/react": "15.0.6",
"@testing-library/jest-dom": "6.6.3",
"@testing-library/react": "16.1.0",
"@testing-library/user-event": "14.5.2",
"@types/jest": "29.5.12",
"@types/node": "20.12.8",
"@types/react": "18.3.1",
"@types/react-dom": "18.3.0",
"@typescript-eslint/eslint-plugin": "7.8.0",
"@typescript-eslint/parser": "7.8.0",
"eslint": "8.54.0",
"eslint-config-prettier": "9.0.0",
"@types/jest": "29.5.14",
"@types/node": "22.10.1",
"@types/react": "19.0.1",
"@types/react-dom": "19.0.2",
"@typescript-eslint/eslint-plugin": "7.18.0",
"@typescript-eslint/parser": "7.18.0",
"eslint": "8.57.1",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-simple-import-sort": "12.1.1",
"eslint-config-react": "1.1.7",
"eslint-plugin-import": "2.29.0",
"eslint-plugin-prettier": "5.0.1",
"eslint-plugin-simple-import-sort": "10.0.0",
"prettier": "3.2.5",
"prettier": "3.4.2",
"react-scripts": "5.0.1",
"typescript": "5.4.5"
"typescript": "5.7.2"
},
"browserslist": {
"production": [
Expand Down
197 changes: 188 additions & 9 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,190 @@
import React, { FC } from 'react';
import Form from './Form';
import StarknetProvider from './StarknetProvider';

const App: FC = () => (
<StarknetProvider>
<Form />
</StarknetProvider>
);
import { FC, useCallback, useEffect, useState } from 'react';
import {
executeCalls,
fetchAccountCompatibility,
fetchAccountsRewards,
fetchGasTokenPrices,
GaslessCompatibility,
GaslessOptions,
GasTokenPrice,
getGasFeesInGasToken,
PaymasterReward,
SEPOLIA_BASE_URL,
} from '@avnu/gasless-sdk';
import { formatUnits } from 'ethers';
import { connect } from 'get-starknet';
import { Account, AccountInterface, Call, EstimateFeeResponse, Provider, stark, transaction } from 'starknet';

const options: GaslessOptions = { baseUrl: SEPOLIA_BASE_URL };
const NODE_URL = 'https://starknet-sepolia.public.blastapi.io';
const initialValue: Call[] = [
{
entrypoint: 'approve',
contractAddress: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
calldata: ['0x0498E484Da80A8895c77DcaD5362aE483758050F22a92aF29A385459b0365BFE', '0xf', '0x0'],
},
];
const isValidJSON = (str: string): boolean => {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
};

const App: FC = () => {
const [account, setAccount] = useState<Account>();
const [loading, setLoading] = useState(false);
const [tx, setTx] = useState<string>();
const [paymasterRewards, setPaymasterRewards] = useState<PaymasterReward[]>([]);
const [calls, setCalls] = useState(JSON.stringify(initialValue, null, 2));
const [gasTokenPrices, setGasTokenPrices] = useState<GasTokenPrice[]>([]);
const [gasTokenPrice, setGasTokenPrice] = useState<GasTokenPrice>();
const [maxGasTokenAmount, setMaxGasTokenAmount] = useState<bigint>();
const [gaslessCompatibility, setGaslessCompatibility] = useState<GaslessCompatibility>();
const [errorMessage, setErrorMessage] = useState<string>();

const handleConnect = async () => {
const starknet = await connect({ modalMode: 'alwaysAsk' });
if (!starknet) return;
await starknet.enable();
if (starknet.isConnected && starknet.provider && starknet.account.address) {
setAccount(starknet.account);
}
};

useEffect(() => {
if (!account) return;
fetchAccountCompatibility(account.address, options).then(setGaslessCompatibility);
fetchAccountsRewards(account.address, { ...options, protocol: 'gasless-sdk' }).then(setPaymasterRewards);
}, [account]);

// The account.estimateInvokeFee doesn't work...
const estimateCalls = useCallback(
async (account: AccountInterface, calls: Call[]): Promise<EstimateFeeResponse> => {
const provider = new Provider({ nodeUrl: NODE_URL });
const contractVersion = await provider.getContractVersion(account.address);
const nonce = await provider.getNonceForAddress(account.address);
const details = stark.v3Details({ skipValidate: true });
const invocation = {
...details,
contractAddress: account.address,
calldata: transaction.getExecuteCalldata(calls, contractVersion.cairo),
signature: [],
};
return provider.getInvokeEstimateFee(invocation, { ...details, nonce, version: 1 }, 'pending', true);
},
[account],
);

// Retrieve estimated gas fees
useEffect(() => {
if (!account || !gasTokenPrice || !gaslessCompatibility) return;
setErrorMessage(undefined);
if (!isValidJSON(calls)) {
setErrorMessage('Invalid calls');
return;
}
const parsedCalls: Call[] = JSON.parse(calls);
estimateCalls(account, parsedCalls).then((fees) => {
const estimatedGasFeesInGasToken = getGasFeesInGasToken(
BigInt(fees.overall_fee),
gasTokenPrice,
BigInt(fees.gas_price!),
BigInt(fees.data_gas_price ?? '0x1'),
gaslessCompatibility.gasConsumedOverhead,
gaslessCompatibility.dataGasConsumedOverhead,
);
setMaxGasTokenAmount(estimatedGasFeesInGasToken * BigInt(2));
});
}, [calls, account, gasTokenPrice, gaslessCompatibility, estimateCalls]);

const onClickExecute = async () => {
if (!account) return;
setLoading(true);
setTx(undefined);
return executeCalls(
account,
JSON.parse(calls),
{
gasTokenAddress: gasTokenPrice?.tokenAddress,
maxGasTokenAmount,
},
options,
)
.then((response) => {
setTx(response.transactionHash);
setLoading(false);
})
.catch((error) => {
setLoading(false);
console.error(error);
});
};

useEffect(() => {
fetchGasTokenPrices(options).then(setGasTokenPrices);
}, []);

if (!account) {
return <button onClick={handleConnect}>Connect Sepolia Wallet</button>;
}

return (
<div>
<p>Connected with account: {account.address}</p>
<p>Execute tx:</p>
<textarea
value={calls}
onChange={(e) => setCalls(e.target.value)}
style={{ minHeight: '500px', minWidth: '1000px' }}
/>
<div>
<p>
<strong>Paymaster rewards</strong>
</p>
{paymasterRewards.length == 0 ? <p>No reward</p> : <p>{JSON.stringify(paymasterRewards)}</p>}
</div>
<div>
<p>
<strong>Gas tokens</strong>
</p>
{paymasterRewards.length > 0 ? (
<p>No gas fees to pay. You have a reward.</p>
) : (
gasTokenPrices.map((price) => (
<button
disabled={price.tokenAddress === gasTokenPrice?.tokenAddress}
onClick={() => setGasTokenPrice(price)}
>
{price.tokenAddress}
</button>
))
)}
</div>
{tx && (
<a href={`https://sepolia.voyager.online/tx/${tx}`} target={'_blank'} rel='noreferrer'>
Success:{tx}
</a>
)}
{errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
{paymasterRewards.length == 0 && !gasTokenPrice && <p>Select a gas token</p>}
{maxGasTokenAmount !== undefined && gasTokenPrice !== undefined && (
<p>Max gas fees in gas token: {formatUnits(maxGasTokenAmount, gasTokenPrice.decimals)}</p>
)}
<div>
{account && (
<button
disabled={!isValidJSON(calls) || loading || (!gasTokenPrice && paymasterRewards.length == 0)}
onClick={onClickExecute}
>
{loading ? 'Loading' : 'Execute'}
</button>
)}
</div>
</div>
);
};

export default App;
20 changes: 0 additions & 20 deletions example/src/Connect.tsx

This file was deleted.

Loading

0 comments on commit 0598877

Please sign in to comment.