-
Notifications
You must be signed in to change notification settings - Fork 15
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
Contract base class and ERC20 class implementations #60
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
5e36cee
WIP ERC20 example (only 'view' functions are implemented)
ptisserand 1aeefab
Move felt to 'types' folder
ptisserand c316bac
Add toSymbol to interpret felt as a string
ptisserand cf416c8
Add uint256 type
ptisserand afad482
Add Contract base class
ptisserand d674319
Add ERC20 implementation with only 'view' methods implemented
ptisserand 9a2de85
examples: update ERC20 to use package provided class
ptisserand 6555c8e
contract: now use account contract `get_nonce` call instead of RPC `s…
ptisserand f71d876
fix(contract): nonce must be increased for each transaction
ptisserand f8f2143
Revert "fix(contract): nonce must be increased for each transaction"
ptisserand 7d4b842
fix(contract): fallback to startknet_getNonce if account contract doe…
ptisserand 1ee1a4b
feat(ERC20): add transfer, transferFrom and approve implementations
ptisserand d280a92
felt: add toHexString method
ptisserand 40d219c
examples/erc20: add `transfer` and `approve` calls
ptisserand File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import 'package:starknet/starknet.dart'; | ||
|
||
final privateKey = Felt.fromInt(1234); | ||
|
||
final accountAddress = Felt.fromHexString( | ||
"0x32d5c7a7953996056caf92ff4dd83f01ad72a3c418c05f15eb2f472d1e9c9f2"); | ||
|
||
final erc20Address = Felt.fromHexString( | ||
"0x4e76f8708774c8162fb4da7abefb3cae94cc51cf3f9b40e0d44f24aabf8a521"); | ||
|
||
final myWalletAddress = Felt.fromHexString( | ||
"0x0367c0c4603a29Bc5aCA8E07C6A2776D7C0d325945aBB4f772f448b345Ca4Cf7"); | ||
|
||
void main() async { | ||
final provider = JsonRpcProvider(nodeUri: infuraGoerliTestnetUri); | ||
|
||
final signer = Signer(privateKey: privateKey); | ||
|
||
final account = Account( | ||
provider: provider, | ||
signer: signer, | ||
accountAddress: accountAddress, | ||
chainId: StarknetChainId.testNet); | ||
|
||
final erc20 = ERC20(account: account, address: erc20Address); | ||
|
||
Future<Uint256> account_balance(Felt account) async { | ||
final balance = await erc20.balanceOf(account); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. woww |
||
print('Balance of ${account.toHexString()}: $balance'); | ||
return balance; | ||
} | ||
|
||
final name = await erc20.name(); | ||
print('Name: $name'); | ||
|
||
final symbol = await erc20.symbol(); | ||
print('Symbol: $symbol'); | ||
|
||
final supply = await erc20.totalSupply(); | ||
print('Supply: $supply'); | ||
|
||
await account_balance(myWalletAddress); | ||
await account_balance(accountAddress); | ||
|
||
final allowance = await erc20.allowance(accountAddress, myWalletAddress); | ||
print('Allowance: $allowance'); | ||
|
||
var trx = await erc20.transfer( | ||
myWalletAddress, | ||
Uint256(low: Felt.fromInt(1), high: Felt.fromInt(0)), | ||
); | ||
print('Transfer Transaction: $trx'); | ||
// wait for transaction .... | ||
trx = await erc20.approve( | ||
myWalletAddress, | ||
Uint256(low: Felt.fromInt(2), high: Felt.fromInt(0)), | ||
); | ||
print('Approve transaction: $trx'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import 'package:starknet/starknet.dart'; | ||
|
||
class Contract { | ||
final Account account; | ||
final Felt address; | ||
|
||
Contract({required this.account, required this.address}); | ||
|
||
Future call(String selector, List<Felt> calldata) async { | ||
final response = await account.provider.call( | ||
request: FunctionCall( | ||
contractAddress: address, | ||
entryPointSelector: getSelectorByName(selector), | ||
calldata: calldata, | ||
), | ||
blockId: BlockId.blockTag("latest"), | ||
); | ||
return (response.when( | ||
error: (error) { | ||
print('Error: $error'); | ||
return null; | ||
}, | ||
result: (result) { | ||
return result; | ||
}, | ||
)); | ||
} | ||
|
||
/// Get Nonce from account contract | ||
Future<Felt> getNonce() async { | ||
final response = await account.provider.call( | ||
request: FunctionCall( | ||
contractAddress: account.accountAddress, | ||
entryPointSelector: getSelectorByName("get_nonce"), | ||
calldata: [], | ||
), | ||
blockId: BlockId.blockTag("latest"), | ||
); | ||
return (response.when(error: (error) async { | ||
if (error.code == 21 && error.message == "Invalid message selector") { | ||
// Fallback on provider getNonce | ||
final nonceResp = | ||
await account.provider.getNonce(account.accountAddress); | ||
return (nonceResp.when( | ||
error: (error) { | ||
throw Exception( | ||
"Error provider getNonce (${error.code}): ${error.message}"); | ||
}, | ||
result: ((result) { | ||
return result; | ||
}), | ||
)); | ||
} else { | ||
throw Exception( | ||
"Error call get_nonce (${error.code}): ${error.message}"); | ||
} | ||
}, result: ((result) { | ||
return result[0]; | ||
}))); | ||
} | ||
|
||
Future<InvokeTransaction> 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: [ | ||
FunctionCall( | ||
contractAddress: address, | ||
entryPointSelector: getSelectorByName(selector), | ||
calldata: calldata, | ||
), | ||
], | ||
nonce: nonce, | ||
maxFee: maxFee, | ||
version: version, | ||
); | ||
return trx; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import 'package:starknet/starknet.dart'; | ||
|
||
class ERC20 extends Contract { | ||
ERC20({required super.account, required super.address}); | ||
|
||
/// Returns the name of the token. | ||
Future<String> name() async { | ||
final res = await call("name", []); | ||
final Felt name = res[0]; | ||
return name.toSymbol(); | ||
} | ||
|
||
/// Returns the symbol of the token, usually a shorter version of the name. | ||
Future<String> symbol() async { | ||
final res = await call("symbol", []); | ||
final Felt symbol = res[0]; | ||
return symbol.toSymbol(); | ||
} | ||
|
||
/// Returns the number of decimals used to get its user representation. | ||
/// | ||
/// For example, if decimals equals 2, a balance of 505 tokens | ||
/// should be displayed to a user as 5,05 (505 / 10 ** 2). | ||
Future<Felt> decimals() async { | ||
final res = await call("decimals", []); | ||
return res; | ||
} | ||
|
||
/// Returns the amount of tokens in existence. | ||
Future<Uint256> totalSupply() async { | ||
final res = await call("totalSupply", []); | ||
return Uint256(low: res[0], high: res[1]); | ||
} | ||
|
||
/// Returns the amount of tokens owned by `account`. | ||
Future<Uint256> balanceOf(Felt account) async { | ||
final res = await call("balanceOf", [account]); | ||
return Uint256(low: res[0], high: res[1]); | ||
} | ||
|
||
/// Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner through transferFrom. | ||
/// | ||
/// This is zero by default. | ||
/// | ||
/// This value changes when approve or transferFrom are called. | ||
Future<Uint256> allowance(Felt owner, Felt spender) async { | ||
final res = await call("allowance", [owner, spender]); | ||
return Uint256(low: res[0], high: res[1]); | ||
} | ||
|
||
/// Moves `amount` tokens from the caller’s account to `recipient`. | ||
/// | ||
/// Returns transaction hash. | ||
Future<String> transfer(Felt recipient, Uint256 value) async { | ||
final InvokeTransaction trx = await execute( | ||
"transfer", | ||
[recipient, value.low, value.high], | ||
); | ||
return (trx.when( | ||
result: (result) { | ||
return result.transaction_hash; | ||
}, | ||
error: (error) { | ||
throw Exception("Error transfer (${error.code}): ${error.message}"); | ||
}, | ||
)); | ||
} | ||
|
||
/// Moves `amount` tokens from `sender` to `recipient` using the allowance mechanism. | ||
/// amount is then deducted from the caller’s allowance. | ||
/// | ||
/// Returns transaction hash. | ||
Future<String> transferFrom(Felt from, Felt to, Uint256 value) async { | ||
final InvokeTransaction trx = await execute( | ||
"transferFrom", | ||
[from, to, value.low, value.high], | ||
); | ||
return (trx.when( | ||
result: (result) { | ||
return result.transaction_hash; | ||
}, | ||
error: (error) { | ||
throw Exception("Error transferFrom (${error.code}): ${error.message}"); | ||
}, | ||
)); | ||
} | ||
|
||
/// Sets `amount` as the allowance of `spender` over the caller’s tokens. | ||
/// | ||
/// Returns transaction hash. | ||
Future<String> approve(Felt spender, Uint256 amount) async { | ||
final InvokeTransaction trx = await execute( | ||
"approve", | ||
[spender, amount.low, amount.high], | ||
); | ||
return (trx.when( | ||
result: (result) { | ||
return result.transaction_hash; | ||
}, | ||
error: (error) { | ||
throw Exception("Error transfer (${error.code}): ${error.message}"); | ||
}, | ||
)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export 'contract.dart'; | ||
export 'erc20.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export 'felt.dart'; | ||
export 'uint256.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import 'package:starknet/starknet.dart'; | ||
|
||
class Uint256 { | ||
final Felt low; // low 128 bits | ||
final Felt high; // high 128 bits | ||
|
||
Uint256({required this.low, required this.high}); | ||
|
||
BigInt toBigInt() { | ||
return (high.toBigInt() << 128) + low.toBigInt(); | ||
} | ||
|
||
@override | ||
String toString() { | ||
return toBigInt().toString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice. I think we could even have factory functions like
Account.Testnet
to speed up the setup :)