deriveContractAddress static method

String deriveContractAddress({
  1. required Uint8List credentialId,
  2. required String deployerPublicKey,
  3. required String networkPassphrase,
})

Derives the smart-account contract address from a credential ID and deployer.

Computes the deterministic contract address that will be created when deploying a smart-account contract with the given credential ID from the specified deployer account on the specified network. The algorithm is:

salt = SHA-256(credentialId)
deployerAddress = SCAddress::Account(deployerPublicKey)
networkId = SHA-256(networkPassphrase as UTF-8)
preimage = HashIDPreimage::ContractID {
  networkId,
  contractIDPreimage: ContractIDPreimage::FromAddress {
    address: deployerAddress,
    salt: Uint256(salt),
  }
}
contractIdBytes = SHA-256(XDR_encode(preimage))
contractId = StrKey.encodeContractId(contractIdBytes)

Throws SmartAccountInvalidAddress when deployerPublicKey is invalid, SmartAccountInvalidInput when contract-ID encoding fails, and SmartAccountTransactionSigningFailed when XDR encoding fails.

Implementation

static String deriveContractAddress({
  required Uint8List credentialId,
  required String deployerPublicKey,
  required String networkPassphrase,
}) {
  final contractSalt = getContractSalt(credentialId);

  XdrSCAddress deployerAddress;
  try {
    // KeyPair.fromAccountId validates the strkey form for us; reuse
    // it so smart-account derivation matches the rest of the SDK.
    KeyPair.fromAccountId(deployerPublicKey);
    deployerAddress = XdrSCAddress.forAccountId(deployerPublicKey);
  } catch (e) {
    throw SmartAccountValidationException.invalidAddress(
      deployerPublicKey,
      cause: e,
    );
  }

  final networkIdBytes = Uint8List.fromList(
    crypto.sha256.convert(utf8.encode(networkPassphrase)).bytes,
  );

  final fromAddress = XdrContractIDPreimageFromAddress(
    deployerAddress,
    XdrUint256(contractSalt),
  );

  final contractIdPreimage = XdrContractIDPreimage(
    XdrContractIDPreimageType.CONTRACT_ID_PREIMAGE_FROM_ADDRESS,
  );
  contractIdPreimage.fromAddress = fromAddress;

  final hashIdPreimageContractId = XdrHashIDPreimageContractID(
    XdrHash(networkIdBytes),
    contractIdPreimage,
  );

  final preimage = XdrHashIDPreimage(
    XdrEnvelopeType.ENVELOPE_TYPE_CONTRACT_ID,
  );
  preimage.contractID = hashIdPreimageContractId;

  Uint8List encodedPreimage;
  try {
    final stream = XdrDataOutputStream();
    XdrHashIDPreimage.encode(stream, preimage);
    encodedPreimage = Uint8List.fromList(stream.bytes);
  } catch (e) {
    throw SmartAccountTransactionException.signingFailed(
      'Failed to XDR encode contract ID preimage',
      cause: e,
    );
  }

  final contractIdBytes = Uint8List.fromList(
    crypto.sha256.convert(encodedPreimage).bytes,
  );

  try {
    return StrKey.encodeContractId(contractIdBytes);
  } catch (e) {
    throw SmartAccountValidationException.invalidInput(
      'contractId',
      'Failed to encode contract ID: $e',
      cause: e,
    );
  }
}