Create and use Generalized Accounts
Introduction
The whole script is located in the repository and this page explains in detail how to:
- initialize an instance of the SDK with a random account,
- top up generated account using faucet on testnet,
- make it a generalized account,
- transfer AE using generalized account.
1. Create SDK instance and generate an account
import {
AeSdk,
Node,
MemoryAccount,
AccountGeneralized,
CompilerHttp,
MIN_GAS_PRICE,
} from '@aeternity/aepp-sdk';
const aeSdk = new AeSdk({
nodes: [{ name: 'testnet', instance: new Node('https://testnet.aeternity.io') }],
accounts: [MemoryAccount.generate()],
onCompiler: new CompilerHttp('https://v8.compiler.aepps.com'),
});
const { address } = aeSdk;
2. Top up generated account using faucet on testnet
const { status } = await fetch(`https://faucet.aepps.com/account/${address}`, { method: 'POST' });
console.assert(status === 200, 'Invalid faucet response code', status);
3. Create a Generalized Account
console.log('Account info before making generalized', await aeSdk.getAccount(address));
const sourceCode = `contract BlindAuth =
stateful entrypoint authorize(shouldAuthorize: bool, _: int) : bool =
switch(Auth.tx_hash)
None => abort("Not in Auth context")
Some(_) => shouldAuthorize
`;
const { gaContractId } = await aeSdk.createGeneralizedAccount('authorize', [], { sourceCode });
console.log('Attached contract address', gaContractId);
bytecode
and aci
options instead of sourceCode
to don't depend on compiler.
console.log(await aeSdk.getAccount(address));
basic
to generalized
, added contractId
,
authFun
fields.
4. Switch SDK instance to AccountGeneralized
After making the account generalized, the node would stop accepting transactions signed using the private key of that account. So, we need to replace the instance of MemoryAccount with AccountGeneralized.
aeSdk.removeAccount(address);
aeSdk.addAccount(new AccountGeneralized(address), { select: true });
5. Transfer AE
Calling the spend
function will create, sign and broadcast a SpendTx
to the network using
AccountGeneralized. It requires authData
option.
console.log('balance before', await aeSdk.getBalance(address));
const authData = { sourceCode, args: [true, 42] };
const recipient = 'ak_21A27UVVt3hDkBE5J7rhhqnH5YNb4Y1dqo4PnSybrH85pnWo7E';
await aeSdk.spend(1e18, recipient, { authData });
console.log('balance after', await aeSdk.getBalance(address));
You may need to put a signed hash of a transaction to authData
, for this purpose you need to
pass a callback in authData
. Use buildAuthTxHash
method to get a hash equal to
Auth.tx_hash
in an authorize entrypoint.
await aeSdk.spend(2e18, recipient, {
async authData(transaction) {
const fee = 10n ** 14n;
const gasPrice = MIN_GAS_PRICE;
const authTxHash = await aeSdk.buildAuthTxHash(transaction, { fee, gasPrice });
console.log('Auth.tx_hash', authTxHash.toString('hex'));
authData.args[1] += 1;
Object.assign(authData, { fee, gasPrice });
return authData;
},
});
console.log('balance after 2nd spend', await aeSdk.getBalance(address));