Extrinsics Service

Extrinsics. This is how you do changes in the blockchain using your account (or its private key).

It all works around making Calls:

open class Call<T: Any>(
    internal val moduleName: String,
    internal val name: String,
    internal val value: T,
    internal val type: KClass<T>
)

We made this as an open class, as we know, you would create many instances for the calls you want. Simply provide in what module this call is in, its function name, set the SCALE codec conforming value and tell us its type to help us unwrap this!

Let us take a AddMemo function from crowdloan pallet as an example:

// Sendable value
data class AddMemo(val index: UInt32, val memo: ByteArray)

// Actual call containing it
class AddMemoCall(value: AddMemo) : Call<AddMemo>(
    moduleName = "crowdloan",
    name = "add_memo",
    value = value,
    type = AddMemo::class
)

To get the call Payload use this:

val client: SubstrateClient
val addMemoIndex: UInt32
val memo: ByteArray

val call: Call<AddMemo> = AddMemoCall(AddMemo(addMemoIndex, memo))
val unsigned: Payload = client.extrinsics.makeUnsigned(call)

Returned Payload is a trivial interface:

interface Payload: ByteArrayConvertible {
    val moduleName: String
    val callName: String
}

Module and call name is provided for our internal library needs, while it also conforms to byte array convertible interface, which we need to tell that this type can convert to byte array.

So you can use received payload to convert it to byte array:

val payload: Payload
val payloadByteArray: ByteArray

This is useful, if you want to create, let's say, batch request. We still haven't implemented this. So if you need it urgently, this is your bro.

To make a signed request there are two different methods.

Using key pair from encrypting library:

val keyPair: KeyPair
val client: SubstrateClient
val call: AddMemoCall

val yourDesiredTip: Int

val signed: Payload = service.makeSigned(
    call = call,
    tip = Balance(BigInteger.valueOf(yourDesiredTip)),
    keyPair = keyPair
)

This way you can get an extrinsic, which you can push using whatever rpc method you want. Or calculate a fee.

If you don't have a key pair, you still need our encrypting library to make your own implementation of SignatureEngine as we need its Signer super-interface. It looks redundant, so we will try to down this requirement to simply Signer in the nearest release.

Or you can specify what kind of our signature engines from the very same library you want to define, like sr25519:

val privateKey: ByteArray
val client: SubstrateClient
val call: AddMemoCall

val yourDesiredTip: Int

val signed: Payload = service.makeSigned(
    call = call,
    tip = Balance(BigInteger.valueOf(yourDesiredTip)),
    accountId = privateKey.sr25519().publicKey.ss58.accountId(),
    signatureEngine = privateKey.sr25519()
)

Mock signed extrinsics

If you want to calculate fee, but don't want to stress test your application by creating actual signature. Feel free to pass a key pair of signature engine with a private key consisting of all bytes equal to 0. For a fee calculation, this won't be a difference.

Last updated