-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #60 from ptisserand/wip-erc20
Contract base class and ERC20 class implementations
- Loading branch information
Showing
8 changed files
with
294 additions
and
1 deletion.
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); | ||
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