Skip to content

Commit

Permalink
Merge pull request #67 from ptisserand/invoke-v1-support
Browse files Browse the repository at this point in the history
Add support for Invoke V1 transaction
  • Loading branch information
ptisserand committed Dec 6, 2022
2 parents f6b3fbc + 37fbbd9 commit 00b4a6d
Show file tree
Hide file tree
Showing 17 changed files with 1,099 additions and 396 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ coverage/

# Python
**/__pycache__
.venv

# Cairo
!contracts/build
!contracts/build

6 changes: 6 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
"request": "launch",
"type": "dart",
"program": "test"
},
{
"name": "Example ERC20",
"request": "launch",
"type": "dart",
"program": "${workspaceFolder}/example/examples/erc20.dart",
}
]
}
128 changes: 112 additions & 16 deletions example/examples/erc20.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,117 @@
import 'package:starknet/starknet.dart';

final privateKey = Felt.fromInt(1234);
class AccountSetup {
final Felt privateKey;
final String accountAddress;
final AccountSupportedTxVersion supportedTxVersion;

final accountAddress = Felt.fromHexString(
"0x32d5c7a7953996056caf92ff4dd83f01ad72a3c418c05f15eb2f472d1e9c9f2");
AccountSetup({
required this.privateKey,
required this.accountAddress,
required this.supportedTxVersion,
});
}

class TestSetup {
final String erc20Address;
final String walletAddress;

TestSetup({
required this.erc20Address,
required this.walletAddress,
});
}

final accountV0Testnet = AccountSetup(
privateKey: Felt.fromInt(1234),
accountAddress:
"0x32d5c7a7953996056caf92ff4dd83f01ad72a3c418c05f15eb2f472d1e9c9f2",
supportedTxVersion: AccountSupportedTxVersion.v0,
);

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

final testnetSetup = TestSetup(
erc20Address:
"0x4e76f8708774c8162fb4da7abefb3cae94cc51cf3f9b40e0d44f24aabf8a521",
walletAddress:
"0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a",
);

final erc20Address = Felt.fromHexString(
"0x4e76f8708774c8162fb4da7abefb3cae94cc51cf3f9b40e0d44f24aabf8a521");
Future<bool> waitForAcceptance(
String transactionHash,
JsonRpcProvider provider,
) async {
bool done = false;
bool succeed = false;
String status = 'PENDING';
final txHash = Felt.fromHexString(transactionHash);
while (done != true) {
final receipt = await provider.getTransactionReceipt(txHash);
//print(receipt);
receipt.when(
result: (result) {
result.map(
declareTxnReceipt: (DeclareTxnReceipt receipt) =>
status = receipt.status,
deployTxnReceipt: (DeployTxnReceipt receipt) =>
status = receipt.status,
deployAccountTxnReceipt: (DeployAccountTxnReceipt receipt) =>
status = receipt.status,
l1HandlerTxnReceipt: (L1HandlerTxnReceipt receipt) =>
status = receipt.status,
pendingDeployTxnReceipt: (PendingDeployTxnReceipt receipt) =>
status = 'PENDING',
pendingCommonReceiptProperties:
(PendingCommonReceiptProperties receipt) => status = 'PENDING',
invokeTxnReceipt: (InvokeTxnReceipt receipt) =>
status = receipt.status,
);
},
error: (error) {
print('An error occured: $error');
done = true;
return false;
},
);
if ('PENDING' == status) {
await Future<void>.delayed(const Duration(seconds: 2));
} else {
if ('ACCEPTED_ON_L2' == status) {
succeed = true;
}
break;
}
}

final myWalletAddress = Felt.fromHexString(
"0x0367c0c4603a29Bc5aCA8E07C6A2776D7C0d325945aBB4f772f448b345Ca4Cf7");
return succeed;
}

void main() async {
final provider = JsonRpcProvider(nodeUri: infuraGoerliTestnetUri);
final accountSetup = accountV0Testnet;
final networkSetup = testnetSetup;
final privateKey = accountSetup.privateKey;
final accountAddress = Felt.fromHexString(accountSetup.accountAddress);
final erc20Address = Felt.fromHexString(networkSetup.erc20Address);
final walletAddress = Felt.fromHexString(networkSetup.walletAddress);

final provider = JsonRpcProvider(nodeUri: devnetUri);

final signer = Signer(privateKey: privateKey);

final account = Account(
provider: provider,
signer: signer,
accountAddress: accountAddress,
chainId: StarknetChainId.testNet);
provider: provider,
signer: signer,
accountAddress: accountAddress,
chainId: StarknetChainId.testNet,
supportedTxVersion: accountSetup.supportedTxVersion,
);

final erc20 = ERC20(account: account, address: erc20Address);

Expand All @@ -39,21 +130,26 @@ void main() async {
final supply = await erc20.totalSupply();
print('Supply: $supply');

await account_balance(myWalletAddress);
await account_balance(walletAddress);
await account_balance(accountAddress);

final allowance = await erc20.allowance(accountAddress, myWalletAddress);
final allowance = await erc20.allowance(accountAddress, walletAddress);
print('Allowance: $allowance');

var trx = await erc20.transfer(
myWalletAddress,
Uint256(low: Felt.fromInt(1), high: Felt.fromInt(0)),
walletAddress,
Uint256(low: Felt.fromInt(2), high: Felt.fromInt(0)),
);
print('Transfer Transaction: $trx');
await waitForAcceptance(trx, provider);
await account_balance(walletAddress);

// wait for transaction ....
/*
trx = await erc20.approve(
myWalletAddress,
Uint256(low: Felt.fromInt(2), high: Felt.fromInt(0)),
);
print('Approve transaction: $trx');
*/
}
16 changes: 6 additions & 10 deletions example/examples/transfer_erc20.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,12 @@ void main() async {
accountAddress: accountAddress,
chainId: StarknetChainId.testNet);

final response = await account.execute(
functionCalls: [
FunctionCall(
contractAddress: erc20Address,
entryPointSelector: getSelectorByName("transfer"),
calldata: [myWalletAddress, Felt.fromInt(1), Felt.fromInt(0)])
],
maxFee: Felt.fromInt(16000000000001),
version: Felt.fromInt(0),
nonce: Felt.fromInt(3));
final response = await account.execute(functionCalls: [
FunctionCall(
contractAddress: erc20Address,
entryPointSelector: getSelectorByName("transfer"),
calldata: [myWalletAddress, Felt.fromInt(1), Felt.fromInt(0)])
], maxFee: Felt.fromInt(16000000000001), nonce: Felt.fromInt(3));

print(response);
}
66 changes: 46 additions & 20 deletions lib/src/account.dart
Original file line number Diff line number Diff line change
@@ -1,43 +1,69 @@
import 'package:starknet/starknet.dart';

enum AccountSupportedTxVersion {
v0,
v1,
}

class Account {
Provider provider;
Signer signer;
Felt accountAddress;
Felt chainId;
AccountSupportedTxVersion supportedTxVersion;

Account({
required this.provider,
required this.signer,
required this.accountAddress,
required this.chainId,
this.supportedTxVersion = AccountSupportedTxVersion.v0,
});

Future<InvokeTransactionResponse> execute({
required List<FunctionCall> functionCalls,
Felt? maxFee,
Felt? nonce,
}) async {
nonce = nonce ?? Felt.fromInt(0);
maxFee = maxFee ?? defaultMaxFee;

Account(
{required this.provider,
required this.signer,
required this.accountAddress,
required this.chainId});

Future<InvokeTransaction> execute(
{required List<FunctionCall> functionCalls,
Felt? maxFee,
Felt? version,
Felt? nonce}) async {
final signature = signer.signTransactions(
transactions: functionCalls,
contractAddress: accountAddress,
version: supportedTxVersion == AccountSupportedTxVersion.v0 ? 0 : 1,
chainId: chainId,
entryPointSelectorName: "__execute__",
maxFee: maxFee,
nonce: nonce);

final calldata = functionCallsToCalldata(
functionCalls: functionCalls, nonce: nonce ?? Felt.fromInt(0));
switch (supportedTxVersion) {
case AccountSupportedTxVersion.v0:
final calldata =
functionCallsToCalldata(functionCalls: functionCalls) + [nonce];

return provider.addInvokeTransaction(
InvokeTransactionRequest(
functionInvocation: FunctionCall(
return provider.addInvokeTransaction(InvokeTransactionRequest(
invokeTransaction: InvokeTransactionV0(
contractAddress: accountAddress,
entryPointSelector: getSelectorByName('__execute__'),
calldata: calldata,
maxFee: maxFee,
signature: signature,
),
));
case AccountSupportedTxVersion.v1:
final calldata = functionCallsToCalldata(functionCalls: functionCalls);

return provider.addInvokeTransaction(
InvokeTransactionRequest(
invokeTransaction: InvokeTransactionV1(
senderAddress: accountAddress,
calldata: calldata,
signature: signature,
maxFee: maxFee,
nonce: nonce),
),
maxFee: maxFee ?? Felt.fromInt(1000000000000000000),
signature: signature,
version: version ?? Felt.fromInt(0)),
);
);
}
}
}
4 changes: 1 addition & 3 deletions lib/src/contract/contract.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,10 @@ class Contract {
})));
}

Future<InvokeTransaction> execute(
Future<InvokeTransactionResponse> execute(
String selector, List<Felt> calldata) async {
final Felt nonce = await getNonce();
final Felt maxFee = defaultMaxFee;
final Felt version = defaultVersion;

final trx = await account.execute(
functionCalls: [
Expand All @@ -78,7 +77,6 @@ class Contract {
],
nonce: nonce,
maxFee: maxFee,
version: version,
);
return trx;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/src/contract/erc20.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ERC20 extends Contract {
///
/// Returns transaction hash.
Future<String> transfer(Felt recipient, Uint256 value) async {
final InvokeTransaction trx = await execute(
final InvokeTransactionResponse trx = await execute(
"transfer",
[recipient, value.low, value.high],
);
Expand All @@ -71,7 +71,7 @@ class ERC20 extends Contract {
///
/// Returns transaction hash.
Future<String> transferFrom(Felt from, Felt to, Uint256 value) async {
final InvokeTransaction trx = await execute(
final InvokeTransactionResponse trx = await execute(
"transferFrom",
[from, to, value.low, value.high],
);
Expand All @@ -89,7 +89,7 @@ class ERC20 extends Contract {
///
/// Returns transaction hash.
Future<String> approve(Felt spender, Uint256 amount) async {
final InvokeTransaction trx = await execute(
final InvokeTransactionResponse trx = await execute(
"approve",
[spender, amount.low, amount.high],
);
Expand Down
4 changes: 1 addition & 3 deletions lib/src/crypto/index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ BigInt computeHashOnElements(List<BigInt> elements) {
}

List<Felt> functionCallsToCalldata(
{required List<FunctionCall> functionCalls, Felt? nonce}) {
nonce = nonce ?? Felt.fromInt(0);
{required List<FunctionCall> functionCalls}) {
List<Felt> calldata = [];
List<Felt> calls = [];
for (final call in functionCalls) {
Expand All @@ -80,6 +79,5 @@ List<Felt> functionCallsToCalldata(
...calls,
Felt.fromInt(calldata.length),
...calldata,
nonce
];
}

0 comments on commit 00b4a6d

Please sign in to comment.