Skip to content

Commit

Permalink
improve soroban auth testing
Browse files Browse the repository at this point in the history
  • Loading branch information
christian-rogobete committed Mar 30, 2023
1 parent eb25d52 commit e156c81
Show file tree
Hide file tree
Showing 7 changed files with 571 additions and 165 deletions.
79 changes: 69 additions & 10 deletions lib/src/soroban/soroban_auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import 'dart:convert';
import 'dart:typed_data';

import '../key_pair.dart';
import '../network.dart';
import '../util.dart';
Expand All @@ -14,27 +13,57 @@ import '../xdr/xdr_type.dart';
import '../xdr/xdr_data_io.dart';

/// Represents a single address in the Stellar network.
///
/// An address can represent an account or a contract.
/// To create an address, call [Address.new]
/// or use [Address.forAccountId] to create an Address for a given accountId
/// or use [Address.forContractId] to create an Address for a given contractId
/// or use [Address.fromXdr] to create an Address for a given [XdrSCAddress].
class Address {

static const int TYPE_ACCOUNT = 0;
static const int TYPE_CONTRACT = 1;

int _type;

/// The type of the Address (TYPE_ACCOUNT or TYPE_CONTRACT).
get type => _type;

/// The id of the account if type is TYPE_ACCOUNT otherwise null.
String? accountId;

/// The id of the contract if type is TYPE_CONTRACT otherwise null.
String? contractId;

Address(this._type, {this.accountId, this.contractId});
/// Constructs an [Address] for the given [type] which can be [Address.TYPE_ACCOUNT] or [Address.TYPE_CONTRACT].
///
/// If [Address.TYPE_ACCOUNT] one must provide [accountId].
/// If [Address.TYPE_CONTRACT] one must provide [contractId].
Address(this._type, {this.accountId, this.contractId}) {
if (this._type != TYPE_ACCOUNT && this._type != TYPE_CONTRACT) {
throw new Exception("unknown type");
}

if (this._type == TYPE_ACCOUNT && this.accountId == null) {
throw new Exception("invalid arguments");
}

if (this._type == TYPE_CONTRACT && this.contractId == null) {
throw new Exception("invalid arguments");
}
}

/// Constructs an [Address] of type [Address.TYPE_ACCOUNT] for the given [accountId].
static Address forAccountId(String accountId) {
return Address(TYPE_ACCOUNT, accountId: accountId);
}

/// Constructs an [Address] of type [Address.TYPE_CONTRACT] for the given [contractId].
static Address forContractId(String contractId) {
return Address(TYPE_CONTRACT, contractId: contractId);
}

/// Constructs an [Address] from the given [xdr].
static Address fromXdr(XdrSCAddress xdr) {
if (xdr.discriminant == XdrSCAddressType.SC_ADDRESS_TYPE_ACCOUNT) {
KeyPair kp = KeyPair.fromXdrPublicKey(xdr.accountId!.accountID);
Expand All @@ -47,6 +76,7 @@ class Address {
}
}

/// Returns a [XdrSCAddress] object created from this [Address] object.
XdrSCAddress toXdr() {
if (_type == TYPE_ACCOUNT) {
if (accountId == null) {
Expand All @@ -63,23 +93,35 @@ class Address {
}
}

/// Returns a [XdrSCVal] containing an [XdrSCObject] for this [Address].
XdrSCVal toXdrSCVal() {
return XdrSCVal.forObject(XdrSCObject.forAddress(toXdr()));
}
}

/// Represents an authorized invocation.
///
/// See Soroban Documentation - Authorization <https://soroban.stellar.org/docs/learn/authorization> for more information.
class AuthorizedInvocation {
String contractId; // The ID of the contract to invoke.
String functionName; // The name of the function to invoke.
List<XdrSCVal> args = List<XdrSCVal>.empty(
growable:
true); // The arguments to pass to the function. array of XdrSCVal.

/// The id of the contract to invoke.
String contractId;

/// The name of the contract function to invoke.
String functionName;

/// The list of arguments to pass to the contract function to be called.
List<XdrSCVal> args = List<XdrSCVal>.empty(growable: true);

/// The list of sub-invocations to pass to the contract function to be called.
List<AuthorizedInvocation> subInvocations = List<AuthorizedInvocation>.empty(
growable:
true); // The sub-invocations to pass to the function. array of AuthorizedInvocation.
growable:true);

/// Constructs an [AuthorizedInvocation] object for the given [contractId]
/// and [functionName] of the contract function to be called.
///
/// Optional list of [args] for the contract function to be called
/// and optional list of [subInvocations] can be provided.
AuthorizedInvocation(this.contractId, this.functionName,
{List<XdrSCVal>? args, List<AuthorizedInvocation>? subInvocations}) {
if (args != null) {
Expand All @@ -90,6 +132,7 @@ class AuthorizedInvocation {
}
}

/// Constructs an [AuthorizedInvocation] from the given [xdr].
static AuthorizedInvocation fromXdr(XdrAuthorizedInvocation xdr) {
List<AuthorizedInvocation> subInvocations =
List<AuthorizedInvocation>.empty(growable: true);
Expand All @@ -101,6 +144,7 @@ class AuthorizedInvocation {
args: xdr.args, subInvocations: subInvocations);
}

/// Returns an [XdrAuthorizedInvocation] object created from this [AuthorizedInvocation] object.
XdrAuthorizedInvocation toXdr() {
List<XdrAuthorizedInvocation> xdrSubs =
List<XdrAuthorizedInvocation>.empty(growable: true);
Expand All @@ -113,10 +157,17 @@ class AuthorizedInvocation {
}

/// Represents a contract authorization.
///
/// See Soroban Documentation - Authorization <https://soroban.stellar.org/docs/learn/authorization> for more information.
class ContractAuth {

/// The root authorized invocation.
AuthorizedInvocation rootInvocation;

/// The signature arguments.
List<XdrSCVal> signatureArgs = List<XdrSCVal>.empty(growable: true);


Address? address;
int? nonce;

Expand All @@ -127,7 +178,9 @@ class ContractAuth {
}
}

/// Sign the contract authorization, the signature will be added to the `signatureArgs`
/// Signs the contract authorization.
///
/// The signature will be added to the [signatureArgs]
/// For custom accounts, this signature format may not be applicable.
/// See Soroban Documentation - Stellar Account Signatures <https://soroban.stellar.org/docs/how-to-guides/invoking-contracts-with-transactions#stellar-account-signatures>
void sign(KeyPair signer, Network network) {
Expand All @@ -150,12 +203,14 @@ class ContractAuth {
signatureArgs.add(signature.toXdrSCVal());
}

/// Constructs a [ContractAuth] from base64 encoded [xdr].
static ContractAuth fromBase64EncodedXdr(String xdr) {
Uint8List bytes = base64Decode(xdr);
return ContractAuth.fromXdr(
XdrContractAuth.decode(XdrDataInputStream(bytes)));
}

/// Constructs a [ContractAuth] from [xdr].
static ContractAuth fromXdr(XdrContractAuth xdr) {
AuthorizedInvocation rootInvocation =
AuthorizedInvocation.fromXdr(xdr.rootInvocation);
Expand All @@ -180,6 +235,7 @@ class ContractAuth {
signatureArgs: argsArr, address: address, nonce: nonce);
}

/// Constructs a list of [ContractAuth] from a list of [XdrContractAuth].
static List<ContractAuth> fromXdrList(List<XdrContractAuth> xdrAuth) {
List<ContractAuth> result = List<ContractAuth>.empty(growable: true);
for (XdrContractAuth next in xdrAuth) {
Expand All @@ -188,6 +244,7 @@ class ContractAuth {
return result;
}

/// Creates an [XdrContractAuth] from this.
XdrContractAuth toXdr() {
XdrAddressWithNonce? addressWithNonce;
if (address != null && nonce != null) {
Expand All @@ -206,6 +263,7 @@ class ContractAuth {
addressWithNonce, rootInvocation.toXdr(), sigArgs);
}

/// Creates a list of [XdrContractAuth] from a list of [ContractAuth].
static List<XdrContractAuth> toXdrList(List<ContractAuth> auth) {
List<XdrContractAuth> result = List<XdrContractAuth>.empty(growable: true);
for (ContractAuth next in auth) {
Expand All @@ -215,6 +273,7 @@ class ContractAuth {
}
}

/// Represents a signature used by [ContractAuth].
class AccountEd25519Signature {
XdrPublicKey publicKey;
Uint8List signatureBytes;
Expand Down
4 changes: 3 additions & 1 deletion soroban.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ SimulateTransactionResponse simulateResponse =

The example above invokes this assembly script [auth contract](https://github.com/Soneso/as-soroban-examples/tree/main/auth#code).

Other examples like [flutter atomic swap](https://github.com/Soneso/stellar_flutter_sdk/blob/master/test/soroban_test_auth.dart#L467) can be found in the [Soroban Auth Test Cases](https://github.com/Soneso/stellar_flutter_sdk/blob/master/test/soroban_test_auth.dart) of the SDK.
Other auth examples can be found in the [Soroban Auth Test Cases](https://github.com/Soneso/stellar_flutter_sdk/blob/master/test/soroban_test_auth.dart) of the SDK.

An advanced auth example can be found in the [flutter atomic swap](https://github.com/Soneso/stellar_flutter_sdk/blob/master/test/soroban_test_atomic_swap.dart) test.

#### Get Events

Expand Down
4 changes: 2 additions & 2 deletions test/query_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void main() {
/// ! get Claimable Balance ID from BID result at claimable_balance_test.dart
Page<OperationResponse> operationsPage = await sdk.operations
.forClaimableBalance(
"00000000b8860382915f2a621bd0e9290a6a4d7753e499cdca1cfba7f4d170d209675840")
"00000000d27ed397b3d3c74e6ced223e26c000029889ac0501f5fae11bf647657a749762")
.limit(1)
.order(RequestBuilderOrder.DESC)
.execute();
Expand All @@ -195,7 +195,7 @@ void main() {
/// ! get Claimable Balance ID from BID result at claimable_balance_test.dart
Page<TransactionResponse> transactionsPage = await sdk.transactions
.forClaimableBalance(
"00000000b8860382915f2a621bd0e9290a6a4d7753e499cdca1cfba7f4d170d209675840")
"00000000d27ed397b3d3c74e6ced223e26c000029889ac0501f5fae11bf647657a749762")
.limit(1)
.order(RequestBuilderOrder.DESC)
.execute();
Expand Down
Loading

0 comments on commit e156c81

Please sign in to comment.