@aptos-labs/ts-sdk
Version:
Aptos TypeScript SDK
104 lines (91 loc) • 3.82 kB
text/typescript
import { sha3_256 } from "@noble/hashes/sha3.js";
import { Serializer } from "../bcs/serializer.js";
import { AccountAddress } from "../core/accountAddress.js";
import { Hex } from "../core/hex.js";
import { AccountAuthenticatorAbstraction } from "../transactions/authenticator/account.js";
import { HexInput, MoveFunctionId } from "../types/index.js";
import { isValidFunctionInfo } from "../utils/helpers.js";
import { AbstractedAccount } from "./AbstractedAccount.js";
type DerivableAbstractedAccountArgs = {
/**
* The signer function signs transactions and returns the `authenticator` bytes in the `AbstractionAuthData`.
*
* @param digest - The SHA256 hash of the transaction signing message
* @returns The `authenticator` bytes that can be used to verify the signature.
*/
signer: (digest: HexInput) => Uint8Array;
/**
* The authentication function that will be used to verify the signature.
*
* @example
* ```ts
* const authenticationFunction = `${accountAddress}::permissioned_delegation::authenticate`;
* ```
*/
authenticationFunction: MoveFunctionId;
/**
* The abstract public key that is used to identify the account.
* Depends on the use cases, most of the time it is the public key of the source wallet
*/
abstractPublicKey: Uint8Array;
};
export class DerivableAbstractedAccount extends AbstractedAccount {
/**
* The abstract public key that is used to identify the account.
* Depends on the use cases, most of the time it is the public key of the source wallet
*/
readonly abstractPublicKey: Uint8Array;
/**
* The domain separator used to calculate the DAA account address.
*/
static readonly ADDRESS_DOMAIN_SEPERATOR: number = 5;
constructor({ signer, authenticationFunction, abstractPublicKey }: DerivableAbstractedAccountArgs) {
const daaAccountAddress = new AccountAddress(
DerivableAbstractedAccount.computeAccountAddress(authenticationFunction, abstractPublicKey),
);
super({
accountAddress: daaAccountAddress,
signer,
authenticationFunction,
});
this.abstractPublicKey = abstractPublicKey;
}
/**
* Compute the account address of the DAA
* The DAA account address is computed by hashing the function info and the account identity
* and appending the domain separator (5)
*
* @param functionInfo - The authentication function
* @param accountIdentifier - The account identity
* @returns The account address
*/
static computeAccountAddress(functionInfo: string, accountIdentifier: Uint8Array): Uint8Array {
if (!isValidFunctionInfo(functionInfo)) {
throw new Error(`Invalid authentication function ${functionInfo} passed into DerivableAbstractedAccount`);
}
const [moduleAddress, moduleName, functionName] = functionInfo.split("::");
const hash = sha3_256.create();
// Serialize and append the function info
const serializer = new Serializer();
AccountAddress.fromString(moduleAddress).serialize(serializer);
serializer.serializeStr(moduleName);
serializer.serializeStr(functionName);
hash.update(serializer.toUint8Array());
// Serialize and append the account identity
const s2 = new Serializer();
s2.serializeBytes(accountIdentifier);
hash.update(s2.toUint8Array());
// Append the domain separator
hash.update(new Uint8Array([DerivableAbstractedAccount.ADDRESS_DOMAIN_SEPERATOR]));
return hash.digest();
}
signWithAuthenticator(message: HexInput): AccountAuthenticatorAbstraction {
const messageBytes = Hex.fromHexInput(message).toUint8Array();
return new AccountAuthenticatorAbstraction(
this.authenticationFunction,
sha3_256(messageBytes),
this.sign(sha3_256(messageBytes)).value,
this.abstractPublicKey,
);
}
}