Skip to content

Commit

Permalink
feat: introduce account signer (#445)
Browse files Browse the repository at this point in the history
* ignore .fvm directory

* feat(starknet): add Account Signer

Account signer is responsible to generate correct signature for a given kind of account contract

* fix(starknet): use relative import

* feat(starknet): use AccountSigner in Account

Signer is deprecated

BREAKING CHANGE: all signature methods are async.

BREAKING CHANGE: AccountSigner doesn't expose proviate key

* melos: add scripts to declare&deploy ERC20 contract

* starknet: update erc20 example to run with devnet

* starknet: remove obsolete example transfer_erc20

* fix(starknet/examples): privateKey is not public for AccountSigner

* starknet: StartAccountSigner export privateKey for testing purpose

* starknet: fix dart analyze

* starknet_cli: fix dart analyze

* walletkit: fix dart analyze

* starknet: remove StarkAccountSigner: privateKey getter

* avnu_provider: fix test to use new AccountSigner

* starknet: add Felt.one and Felt.two

* feat(starknet): add support for ArgentX account without guardian

* feat(starknet): add ArgentX 0.4.0 account deploy on devnet example

* apply some coderabbit suggestions
  • Loading branch information
ptisserand authored Feb 18, 2025
1 parent bc698d7 commit 61b2192
Show file tree
Hide file tree
Showing 42 changed files with 1,198 additions and 972 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ coverage/
.starkli/account_1.json
pubspec_overrides.yaml
*.iml

.fvm
2 changes: 1 addition & 1 deletion docs/packages/avnu_provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ final accountClassHash = (await provider.getClassHashAt(
))
.when(
result: (result) => result.toHexString(),
error: (error) => Felt.fromInt(0).toHexString(),
error: (error) => Felt.zero.toHexString(),
);
// Build the typed data
Expand Down
9 changes: 9 additions & 0 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ scripts:
starkli invoke eth transfer 0x016a0d7df981d681537dc2ce648722ff1d1c2cbe59412b492d35bac69825f104 0x100000000000000000 0x0
echo | starkli account deploy .starkli/account_1.json
contracts:token:declare:
description: declare the ERC20 contract
run: |
starkli declare contracts/v$CAIRO_VERSION/target/dev/contract2_MyToken.contract_class.json --compiler-version $CAIRO_VERSION 2>&1
contracts:token:deploy:
description: deploy the ERC20 contract
run: |
starkli deploy --salt 0x12345678 0x07d4ee0e4494fe12b26da8e7d2cb114185f768f2bce3e7b1b356cecc9596474b u256:1000000000000000000000000000 0x64b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691 2>&1
test:
description: Run all tests
steps:
Expand Down
26 changes: 13 additions & 13 deletions packages/ark_project/lib/src/ark_starknet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ class ArkStarknet {
...computeCalldata(order.offerer),
...computeCalldata(order.tokenChainId),
...computeCalldata(order.tokenAddress),
Felt.fromInt(0),
Felt.zero,
Felt(tokenIdBigInt),
...computeCalldata(order.quantity),
...computeCalldata(order.startAmount),
...computeCalldata(order.endAmount),
Felt.fromInt(0),
Felt.zero,
...computeCalldata(order.startDate),
...computeCalldata(order.endDate),
...computeCalldata(order.brokerId),
Expand All @@ -85,7 +85,7 @@ class ArkStarknet {
FunctionCall(
contractAddress: Felt.fromHexString(nftAddress),
entryPointSelector: getSelectorByName('approve'),
calldata: [arkExecutorAddress, Felt(tokenIdBigInt), Felt.fromInt(0)],
calldata: [arkExecutorAddress, Felt(tokenIdBigInt), Felt.zero],
),
FunctionCall(
contractAddress: arkExecutorAddress,
Expand Down Expand Up @@ -131,7 +131,7 @@ class ArkStarknet {
...computeCalldata(fullCancelInfo.canceller),
...computeCalldata(fullCancelInfo.tokenChainId),
...computeCalldata(fullCancelInfo.tokenAddress),
Felt.fromInt(0),
Felt.zero,
...computeCalldata(fullCancelInfo.tokenId),
];

Expand Down Expand Up @@ -208,12 +208,12 @@ class ArkStarknet {
...computeCalldata(order.offerer),
...computeCalldata(order.tokenChainId),
...computeCalldata(order.tokenAddress),
Felt.fromInt(0),
Felt.zero,
Felt(tokenIdBigInt),
...computeCalldata(order.quantity),
...computeCalldata(order.startAmount),
...computeCalldata(order.endAmount),
Felt.fromInt(0),
Felt.zero,
...computeCalldata(order.startDate),
...computeCalldata(order.endDate),
...computeCalldata(order.brokerId),
Expand All @@ -225,7 +225,7 @@ class ArkStarknet {
FunctionCall(
contractAddress: Felt.fromHexString(currencyAddress),
entryPointSelector: getSelectorByName('approve'),
calldata: [arkExecutorAddress, Felt(bigIntAmount), Felt.fromInt(0)],
calldata: [arkExecutorAddress, Felt(bigIntAmount), Felt.zero],
),
FunctionCall(
contractAddress: arkExecutorAddress,
Expand Down Expand Up @@ -282,9 +282,9 @@ class ArkStarknet {
...computeCalldata(fulfillInfo.fulfiller),
...computeCalldata(fulfillInfo.tokenChainId),
...computeCalldata(fulfillInfo.tokenAddress),
Felt.fromInt(0),
Felt.zero,
Felt(tokenIdBigInt),
Felt.fromInt(0),
Felt.zero,
...computeCalldata(fulfillInfo.fulfillBrokerAddress),
];

Expand All @@ -293,7 +293,7 @@ class ArkStarknet {
FunctionCall(
contractAddress: Felt.fromHexString(currencyAddress),
entryPointSelector: getSelectorByName('approve'),
calldata: [arkExecutorAddress, Felt(bigIntAmount), Felt.fromInt(0)],
calldata: [arkExecutorAddress, Felt(bigIntAmount), Felt.zero],
),
FunctionCall(
contractAddress: arkExecutorAddress,
Expand Down Expand Up @@ -347,9 +347,9 @@ class ArkStarknet {
...computeCalldata(fulfillInfo.fulfiller),
...computeCalldata(fulfillInfo.tokenChainId),
...computeCalldata(fulfillInfo.tokenAddress),
Felt.fromInt(0),
Felt.zero,
Felt(tokenIdBigInt),
Felt.fromInt(0),
Felt.zero,
...computeCalldata(fulfillInfo.fulfillBrokerAddress),
];

Expand All @@ -358,7 +358,7 @@ class ArkStarknet {
FunctionCall(
contractAddress: Felt.fromHexString(nftAddress),
entryPointSelector: getSelectorByName('approve'),
calldata: [arkExecutorAddress, Felt(tokenIdBigInt), Felt.fromInt(0)],
calldata: [arkExecutorAddress, Felt(tokenIdBigInt), Felt.zero],
),
FunctionCall(
contractAddress: arkExecutorAddress,
Expand Down
33 changes: 12 additions & 21 deletions packages/avnu_provider/test/integration/provider_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,13 @@ void main() {

final messageHash = getMessageHash(
typedDataObject, sepoliaAccount0.accountAddress.toBigInt());
final signature = starknetSign(
privateKey: sepoliaAccount0.signer.privateKey.toBigInt(),
messageHash: messageHash,
seed: BigInt.from(32),
);
final signature =
await sepoliaAccount0.signer.sign(messageHash, BigInt.from(32));
final signCount = "0x1";
final starknetSignatureId = "0x0";
final publicKey = sepoliaAccount0.signer.publicKey.toHexString();
final signatureR = Felt(signature.r).toHexString();
final signatureS = Felt(signature.s).toHexString();
final signatureR = signature[0].toHexString();
final signatureS = signature[1].toHexString();
final signatureList = [
signCount,
starknetSignatureId,
Expand Down Expand Up @@ -149,16 +146,13 @@ void main() {

final messageHash = getMessageHash(
typedDataObject, sepoliaAccount0.accountAddress.toBigInt());
final signature = starknetSign(
privateKey: sepoliaAccount0.signer.privateKey.toBigInt(),
messageHash: messageHash,
seed: BigInt.from(32),
);
final signature =
await sepoliaAccount0.signer.sign(messageHash, BigInt.from(32));
final signCount = "0x1";
final starknetSignatureId = "0x0";
final publicKey = sepoliaAccount0.signer.publicKey.toHexString();
final signatureR = Felt(signature.r).toHexString();
final signatureS = Felt(signature.s).toHexString();
final signatureR = signature[0].toHexString();
final signatureS = signature[1].toHexString();
final signatureList = [
signCount,
starknetSignatureId,
Expand Down Expand Up @@ -243,16 +237,13 @@ void main() {
// Generate signature for the typed data
final messageHash = getMessageHash(
typedDataObject, sepoliaAccount0.accountAddress.toBigInt());
final signature = starknetSign(
privateKey: sepoliaAccount0.signer.privateKey.toBigInt(),
messageHash: messageHash,
seed: BigInt.from(32),
);
final signature =
await sepoliaAccount0.signer.sign(messageHash, BigInt.from(32));
final signCount = "0x1";
final starknetSignatureId = "0x0";
final publicKey = sepoliaAccount0.signer.publicKey.toHexString();
final signatureR = Felt(signature.r).toHexString();
final signatureS = Felt(signature.s).toHexString();
final signatureR = signature[0].toHexString();
final signatureS = signature[1].toHexString();
final signatureList = [
signCount,
starknetSignatureId,
Expand Down
36 changes: 17 additions & 19 deletions packages/starknet/example/examples/deploy_openzeppelin.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import 'dart:io';

import 'package:starknet/starknet.dart';
import 'package:bip39/bip39.dart' as bip39;
import 'package:starknet/starknet.dart';
import 'package:starknet_provider/starknet_provider.dart';

Future<void> printAccountInfo(Account account) async {
print("Address: ${account.accountAddress.toHexString()}");
print("Public key: ${account.signer.publicKey.toHexString()}");
print("Private key: ${account.signer.privateKey.toHexString()}");
print('Address: ${account.accountAddress.toHexString()}');
print('Public key: ${account.signer.publicKey.toHexString()}');
final balance = await account.balance();
print("Balance: ${balance.toBigInt().toDouble() * 1e-18}");
print('Balance: ${balance.toBigInt().toDouble() * 1e-18}');
}

String generateMnemonic() {
Expand All @@ -19,8 +18,8 @@ String generateMnemonic() {
void main() async {
// for testnet
final recoveryMnemonic =
"toward antenna indicate reject must artist expect angry fit easy cupboard require"
.split(" ");
'toward antenna indicate reject must artist expect angry fit easy cupboard require'
.split(' ');
final provider = JsonRpcProvider(nodeUri: infuraGoerliTestnetUri);
final chainId = StarknetChainId.testNet;
final fundingAccount = Account.fromMnemonic(
Expand All @@ -29,47 +28,46 @@ void main() async {
chainId: chainId,
index: 0,
);
print("Recovery account:");
print('Recovery account:');
await printAccountInfo(fundingAccount);

final proxyClassHash = ozProxyClassHash;
final implementationClassHash = ozAccountUpgradableClassHash;
print("Proxy class hash: ${proxyClassHash.toHexString()}");
print("Account class hash: ${implementationClassHash.toHexString()}");
print('Proxy class hash: ${proxyClassHash.toHexString()}');
print('Account class hash: ${implementationClassHash.toHexString()}');
final mnemonic = generateMnemonic();
print("Mnemonic: $mnemonic");
print('Mnemonic: $mnemonic');
final accountDerivation = OpenzeppelinAccountDerivation(
proxyClassHash: proxyClassHash,
implementationClassHash: implementationClassHash,
);
final account = Account.fromMnemonic(
mnemonic: mnemonic.split(" "),
mnemonic: mnemonic.split(' '),
provider: provider,
chainId: StarknetChainId.testNet,
accountDerivation: accountDerivation,
);

print(
"Sending funds to new account address ${account.accountAddress.toHexString()}",
'Sending funds to new account address ${account.accountAddress.toHexString()}',
);

final txHash = await fundingAccount.send(
recipient: account.accountAddress,
amount:
Uint256(low: Felt(BigInt.from(0.005 * 1e18)), high: Felt.fromInt(0)),
amount: Uint256(low: Felt(BigInt.from(0.005 * 1e18)), high: Felt.zero),
);
bool isAccepted =
await waitForAcceptance(transactionHash: txHash, provider: provider);
if (!isAccepted) {
print("Sending funds failed ($txHash)");
print('Sending funds failed ($txHash)');
return;
}

try {
final deployTxHash = await accountDerivation.deploy(account: account);
print("#####################################");
print("Mnemonic: $mnemonic");
print("Wait for deployed account transaction");
print('#####################################');
print('Mnemonic: $mnemonic');
print('Wait for deployed account transaction');
final isAccepted = await waitForAcceptance(
transactionHash: deployTxHash.toHexString(),
provider: provider,
Expand Down
49 changes: 23 additions & 26 deletions packages/starknet/example/examples/erc20.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
// example of ERC20 interaction
//
// In repository top directoryn run the following:
// source .env.devnet
// melos starknet:setup
// melos devnet:start
//
// In another terminal
// source .env.devnet
// melos contracts:build
// melos contracts:token:declare
// melos contracts:token:deploy
import 'package:starknet/starknet.dart';
import 'package:starknet_provider/starknet_provider.dart';

Expand Down Expand Up @@ -25,39 +37,23 @@ class TestSetup {
});
}

final accountV0Testnet = AccountSetup(
privateKey: Felt.fromInt(1234),
final accountDevnet = AccountSetup(
privateKey: Felt.fromHexString('0x71d7bb07b9a64f6f78ac4c816aff4da9'),
accountAddress:
"0x32d5c7a7953996056caf92ff4dd83f01ad72a3c418c05f15eb2f472d1e9c9f2",
// ignore: deprecated_member_use_from_same_package
supportedTxVersion: AccountSupportedTxVersion.v0,
);

final accountV1Testnet = AccountSetup(
privateKey: Felt(BigInt.parse(
"888585928659514599423272828715188693704171690573707019357972128231005959671")),
accountAddress:
"0x04FF446995457B7Cd0E0A54De94426E27CB253F556fE3a2025304Ba4FD5D60D0",
'0x64b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691',
supportedTxVersion: AccountSupportedTxVersion.v1,
);

final testnetSetup = TestSetup(
erc20Address:
"0x4e76f8708774c8162fb4da7abefb3cae94cc51cf3f9b40e0d44f24aabf8a521",
walletAddress:
"0x04FF446995457B7Cd0E0A54De94426E27CB253F556fE3a2025304Ba4FD5D60D0",
nodeUri: infuraGoerliTestnetUri,
);

final devnetSetup = TestSetup(
erc20Address:
"0x4e76f8708774c8162fb4da7abefb3cae94cc51cf3f9b40e0d44f24aabf8a521",
'0x0459e98338624655a2d70a6027ad2ecdced346b221feaf97066139f2100294ee',
walletAddress:
"0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a",
'0x78662e7352d062084b0010068b99288486c2d8b914f6e2a55ce945f8792c8b1',
nodeUri: devnetUri,
);

void main() async {
final accountSetup = accountV1Testnet;
final accountSetup = accountDevnet;
final networkSetup = devnetSetup;
final privateKey = accountSetup.privateKey;
final accountAddress = Felt.fromHexString(accountSetup.accountAddress);
Expand All @@ -67,7 +63,8 @@ void main() async {

final provider = JsonRpcProvider(nodeUri: nodeUri);

final signer = Signer(privateKey: privateKey);
final signer =
StarkAccountSigner(signer: StarkSigner(privateKey: privateKey));

final account = Account(
provider: provider,
Expand Down Expand Up @@ -102,7 +99,7 @@ void main() async {

var trx = await erc20.transfer(
walletAddress,
Uint256(low: Felt.fromInt(2), high: Felt.fromInt(0)),
Uint256(low: Felt.two, high: Felt.zero),
);
print('Transfer Transaction: $trx');
var accepted = await waitForAcceptance(
Expand All @@ -115,7 +112,7 @@ void main() async {
final new_allowance = Felt(allowance.low.toBigInt() + BigInt.from(1));
trx = await erc20.approve(
walletAddress,
Uint256(low: new_allowance, high: Felt.fromInt(0)),
Uint256(low: new_allowance, high: Felt.zero),
);
print('Approve transaction: $trx');
accepted = await waitForAcceptance(
Expand Down
Loading

0 comments on commit 61b2192

Please sign in to comment.