Flow Interaction ADT and Helpers
npm install @onflow/interactionThis module provides an ADT (Abstract Data Type) that represents the underlying data required by the send function. It provides function in which to modify the interaction.
- Last Updated: Feb 2nd 2021
- Stable: Yes
- Risk of Breaking Change: Medium
This is a keystone data structure in how the SDK works. We will strive for backwards compatibility in any changes to this, as it also makes our lives easier.
Now that we have a stable encoding package for creating what needs to be signed in transactions, we will be bringing this data structure closer to what those functions need.
Known Upcoming Changes:
- We will be changing some of the underlying fields and data so they are more inline with @onflow/encode
``bash`
npm install --save @onflow/interaction
Currently the Access Node recognizes 7 different types of interactions.
- Script executes a script, can be used to query Flow
- Transaction executes a transaction
- GetTransactionStatus requests the status of a supplied transaction
- GetAccount requests a supplied account
- GetEvents requests events of a supplied type
- GetLatestBlock requests the latest block
- Ping requests a pong
- GetTransaction requests a transaction
- GetBlockById requests a block by an ID deprecated, use GetBlock instead
- GetBlockByHeight requests a block by a height deprecated, use GetBlock instead
- GetBlock requests a block
- GetBlockHeader requests a block header
> The interaction is a monomorphic data structure, that merges the 7 types of interactions together. Internally it has a bunch of properties, but not everything needs to be included for each of the 7 interaction types.
- tag _(all)_ Int -- a marker that represents the type of the interactionInt
- status _(all)_ -- a marker that represents the status of the interactionString
- reason _(all)_ -- used to supply more information/feedback when a status is badInt
- accounts _(transaction, script)_
- kind _(transaction, script)_ -- denotes the kind of account, ACCOUNT or PARAM or ARGUMENTString
- tempId _(transaction, script)_ -- denotes the internal tempId for this accountString
- addr _(transaction, script)_ -- denotes the address of this accountInt
- keyId _(transaction, script)_ -- denotes the keyId in question for this accountInt
- sequenceNum _(transaction, script)_ -- denotes the sequenceNum in question for this accountString
- signature _(transaction, script)_ -- the signature produced by the signingFunction for this accountFunction
- signingFunction _(transaction, script)_ -- the signing function for this accountFunction
- resolve _(transaction, script)_ -- the resolver for this accountBoolean
- role _(transaction, script)_
- propser _(transaction, script)_ -- denotes if this account is a propserBoolean
- authorizer _(transaction, script)_ -- denotes if this account is an authorizerBoolean
- payer _(transaction, script)_ -- denotes if this account is a payerBoolean
- param _(transaction, script)_ -- denotes if this account is a paramInt
- params _(transaction, script)_
- kind _(transaction, script)_ -- denotes the kind of param, ACCOUNT or PARAM or ARGUMENTString
- tempId _(transaction, script)_ -- the internal tempId for this paramString
- key _(transaction, script)_ -- the key for this paramAny
- value _(transaction, script)_ -- the value for this paramAny
- asParam _(transaction, script)_ -- the asParam transformed value for this paramAny
- xform _(transaction, script)_ -- the transform for this paramFunction
- resolve _(transaction, script)_ -- a resolver for this paramInt
- arguments _(transaction, script)_
- kind _(transaction, script)_ -- denotes the kind of argument, ACCOUNT or PARAM or ARGUMENTString
- tempId _(transaction, script)_ -- the internal tempId for this argumentAny
- value _(transaction, script)_ -- the value for this argumentAny
- asArgument _(transaction, script)_ -- the asArgument transformed value for this argumentAny
- xform _(transaction, script)_ -- the transform for this argumentFunction
- resolve _(transaction, script)_ -- a resolver for this argumentString
- message _(script, transaction)_
- cadence _(script, transaction)_ -- cadence codeString
- refBlock _(transaction)_ -- id of an existing block (used for timeout)Int
- computeLimit _(script)_ -- how much payer is willing to spendString
- proposer _(transaction)_ -- the tempId of the account proposer for a transactionString
- payer _(transaction)_ -- the tempId of the payer for a transactionArray
- authorizations _(transaction)_ -- list of tempIds referencing the accounts of the authorizers for a transactionArray
- params _(transaction, script)_ -- list of tempIds referencing the params for a transaction or scriptArray
- arguments _(transaction, script)_ -- list of tempIds referencing the arguments for a transaction or scriptString
- proposer _(transaction)_ -- the tempId referencing the account of the proposer for a transactionString
- payer _(transaction)_ -- the tempId referencing the account of the payer for a transactionArray
- authorizations _(transaction)_ -- list of tempIds referencing the accounts of the authorizers for a transactionInt
- events _(getEvents)_
- start _(getEvents)_ -- events after thisInt
- end _(getEvents)_ -- events before thisString
- eventType _(getEvents)_ -- type of events to getArray
- blockIds _(getEvents)_ -- array of block ids to get events fromBoolean
- block _(getLatestBlock, getBlockByHeight, getBlockById)_
- isSealed _(getLatestBlock)_ -- determines if the criteria for the latest block is sealed or not.Int
- height _(getBlockByHeight)_ -- sets the height for the block to get.Int
- id _(getBlockById)_ -- sets the id for the block to get.String
- account
- addr _(getAccount) -- address of the account to get{[String]:Any}
- transaction
- id _(getTransaction) -- id of the transaction to get
- assigns _(all)_ -- a pocket to hold things in while building and resolving
Tags
| Label | asString |
| ----------------------: | :-------------------------: |
| UNKNOWN | UNKNOWN |
| SCRIPT | SCRIPT |
| TRANSACTION | TRANSACTION |
| GET_TRANSACTION_STATUS | GET_TRANSACTION_STATUS |
| GET_ACCOUNT | GET_ACCOUNT |
| GET_EVENTS | GET_EVENTS |
| GET_LATEST_BLOCK | GET_LATEST_BLOCK |
| PING | PING |
| PING | PING |
| GET_TRANSACTION | GET_TRANSACTION |
| GET_BLOCK_BY_ID | GET_BLOCK_BY_ID |
| GET_BLOCK | GET_BLOCK |
| GET_BLOCK_HEADER | GET_BLOCK_HEADER |
Status
| Label | asString |
| ----: | :------: |
| BAD | BAD |
| OK | OK |
- Constructor
- interaction/0
- isInteraction/1
- Control
- Ok/1
- isOk/1
- Bad/2
- isBad/1
- why/1
- Tags
- Unknown
- makeUnknown/1
- isUnknown/1
- Script
- makeScript/1
- isScript/1
- Transaction
- makeTransaction/1
- isTransaction/1
- GetTransactionStatus
- makeGetTransactionStatus/1
- isGetTransactionStatus/1
- GetAccount
- makeGetAccount/1
- isGetAccount/1
- GetEvents
- makeGetEvents/1
- isGetEvents/1
- GetLatestBlock
- makeGetLatestBlock/1
- isGetLatestBlock/1
- GetBlock
- makeGeBlock/1
- isGetBlock/1
- Ping
- makePing/1
- isPing/1
- GetTransaction
- makePing/1
- isPing/1
- GetBlock
- makePing/1
- isPing/1
- GetBlockHeader
- makePing/1
- isPing/1
- Assigns
- get/3
- put/2
- update/2
- destroy/1
- Accounts
- makeAuthorizer/1
- makePayer/1
- makeProposer/1
- Params
- makeParam/1
- Composition
- pipe/2
- pipe/1
> Constructs an empty interaction.
`javascript
import {interaction} from "@onflow/interaction"
const emptyInteraction = interaction()
`
> returns true if the value passed to it is an interaction
`javascript
import {interaction, isInteraction} from "@onflow/interaction"
const ix = interaction()
isInteraction(ix) // true
isInteraction("i am a string") // false
`
> Sets the status of an interaction to OK
`javascript
import {interaction, Ok, isOk} from "@onflow/interaction"
isOk(Ok(interaction())) // true
`
> Sets the status of an interaction to BAD, can also add a reason as to why its bad.
`javascript
import {interaction, Bad, why} from "@onflow/interaction"
const ix = Bad(interaction, "You were supposed to do the thing")
isBad(ix) // true
why(ix) // "You were supposed to do the thing"
`
> tags an interaction as Unknown
`javascript
import {interaction, makeUnknown, isUnknown} from "@onflow/interaction"
isUnknown(makeUnknown(interaction())) // true
`
> tags an interaction as a Script interaction
`javascript
import {interaction, makeScript, isScript} from "@onflow/interaction"
isScript(makeScript(interaction())) // true
`
> tags an interaction as a Transaction interaction
`javascript
import {interaction, makeTransaction, isTransaction} from "@onflow/interaction"
isTransaction(makeTransaction(interaction())) // true
`
> tags an interaction as a GetTransactionStatus interaction
`javascript
import {
interaction,
makeGetTransactionStatus,
isGetTransactionStatus,
} from "@onflow/interaction"
isGetTransactionStatus(makeGetTransactionStatus(interaction())) // true
`
> tags an interaction as a GetAccount interaction
`javascript
import {interaction, makeGetAccount, isGetAccount} from "@onflow/interaction"
isGetAccount(makeGetAccount(interaction())) // true
`
> tags an interaction as a GetEvents interaction
`javascript
import {interaction, makeGetEvents, isGetEvents} from "@onflow/interaction"
isGetEvents(makeGetEvents(interaction())) // true
`
> tags an interaction as a GetLatestBlock interaction
`javascript
import {
interaction,
makeGetLatestBlock,
isGetLatestBlock,
} from "@onflow/interaction"
isGetLatestBlock(makeGetLatestBlock(interaction())) // true
`
> tags an interaction as a Ping interaction
`javascript
import {interaction, makePing, isPing} from "@onflow/interaction"
isPing(makePing(interaction())) // true
`
> tags an interaction as a GetTransaction interaction
`javascript
import {interaction, makeGetTransaction, isGetTransaction} from "@onflow/interaction"
isGetTransaction(makeGetTransaction(interaction())) // true
`
> tags an interaction as a GetBlock interaction
`javascript
import {interaction, makeGetBlock, isGetBlock} from "@onflow/interaction"
isGetBlock(makeGetBlock(interaction())) // true
`
> tags an interaction as a GetBlockHeader interaction
`javascript
import {interaction, makeGetBlockHeader, isGetBlockHeader} from "@onflow/interaction"
isGetBlockHeader(makeGetBlockHeader(interaction())) // true
`
> crud operations for the assigns pocket inside the interaction. They are specifically designed to be used with pipe.
`javascript
import {interaction, get, put, update, destory} from "@onflow/interaction"
let ix = interaction()
get(ix, "count", 0) // 0
ix = put("count", 0)(ix)
get(ix, "count", 0) // 0
ix = update("count", count => count + 1)(ix)
get(ix, "count", 0) // 1
ix = destory("count")(ix)
get(ix, "count", 0) // 0
`
javascript
import {makeAuthorizer, makeTransaction, pipe} from "@onflow/interaction"
const ix = pipe([
makeTransaction
makeAuthorizer({ addr: "01", role: { authorizer: true } })
])
`$3
> compose a Payer account, and registers a tempId for it in the interaction object accounts registry
`javascript
import {makePayer, makeTransaction, pipe} from "@onflow/interaction"
const ix = pipe([
makeTransaction
makePayer({ addr: "01", role: { payer: true } })
])
`$3
> compose a Proposer account, and registers a tempId for it in the interaction object accounts registry
`javascript
import {makeProposer, makeTransaction, pipe} from "@onflow/interaction"
const ix = pipe([
makeTransaction
makeProposer({ addr: "01", role: { proposer: true } })
])
`$3
> compose a Param, and registers a tempId for it in the interaction object params registry
`javascript
import {makeParam, makeTransaction, pipe} from "@onflow/interaction"
const ix = pipe([
makeTransaction
makeParam(...)
])
`$3
> asynchronously composes transform functions and applys them to an interaction.
`javascript
import {interaction, pipe, put, update} from "@onflow/interaction"const ix = await pipe(interaction(), [
put("a", 5),
put("b", 6),
update("sum", (_, ix) => get(ix, "a", 0) + get(ix, "b", 0)),
])
get(ix, "sum", 0) // 11
`$3
> gets passed an array of transform functions, returning a function that takes an interaction to apply the transform functions to asynchronously.
`javascript
import {interaction, pipe, put, update} from "@onflow/interaction"const run = await pipe([
put("a", 5),
put("b", 6),
update("sum", (_, ix) => get(ix, "a", 0) + get(ix, "b", 0)),
])
const ix = run(interaction())
get(ix, "sum", 0) // 11
// Pipes can also be composed
const p1 = pipe([put("a", 1), put("b", 2)])
const p2 = pipe([put("c", 3), put("d", 4)])
const calc = update("sum", (_, ix) =>
["a", "b", "c", "d"].reduce((acc, d) => acc + get(ix, d, 0), 0)
)
const ix = await pipe(interaction(), [p1, p2, calc])
get(ix, "sum", 0) // 10
// Pipes can be stoped
import {Bad, Ok, isBad, why} from "@onflow/interaction"
const countCantBeGreaterThan = value => ix =>
get(ix, "count", 0) > value ? Bad(ix,
Was greater than ${value}) : Ok(ix)const setCount = count => put("count", count)
const incCountBy = amount => update("count", count => count + amount)
const ix = await pipe(interaction(), [
setCount(5), // count: 5
countCantBeGreaterThan(10), // Ok
incCountBy(3), // count: 8
countCantBeGreaterThan(10), // Ok
incCountBy(5), // count: 13
countCantBeGreaterThan(10), // Bad
incCountBy(9), // never called
])
isBad(ix) // true
why(ix) // "Was greater than 10"
``