add descriptions for workflows and inputs
This commit is contained in:
parent
4832300098
commit
af9babe526
|
@ -24,15 +24,45 @@ pub enum WorkflowError {
|
||||||
InvocationError(String),
|
InvocationError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An input for a workflow argument. When inputs are read, they should be referenced by the first
|
||||||
|
/// name. Additional names can be provided as aliases, to allow chaining workflows together when
|
||||||
|
/// names may not make sense - such as a Solana address then being used as an authorization
|
||||||
|
/// address.
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct Input {
|
||||||
|
/// An input with a single identifier.
|
||||||
|
/// The name of the input.
|
||||||
|
pub name: String,
|
||||||
|
|
||||||
|
/// A description of the input.
|
||||||
|
pub description: String,
|
||||||
|
|
||||||
|
/// Aliases used when loading inputs.
|
||||||
|
#[serde(default)]
|
||||||
|
pub aliases: Vec<String>,
|
||||||
|
|
||||||
|
/// Whether the workflow input is optional.
|
||||||
|
pub optional: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
pub fn identifiers(&self) -> impl Iterator<Item = &String> {
|
||||||
|
[&self.name].into_iter().chain(self.aliases.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_required(&self) -> bool {
|
||||||
|
self.optional.is_some_and(|o| o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Workflow {
|
pub struct Workflow {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
#[serde(default)]
|
pub description: String,
|
||||||
pub inputs: Vec<String>,
|
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub optional_inputs: Vec<String>,
|
pub inputs: Vec<Input>,
|
||||||
|
|
||||||
#[serde(rename = "step")]
|
#[serde(rename = "step")]
|
||||||
steps: Vec<WorkflowStep>,
|
steps: Vec<WorkflowStep>,
|
||||||
|
|
|
@ -20,6 +20,7 @@ fn main() {
|
||||||
|
|
||||||
for module_dir in std::fs::read_dir(&workflows_dir).unwrap() {
|
for module_dir in std::fs::read_dir(&workflows_dir).unwrap() {
|
||||||
let module_dir = module_dir.unwrap();
|
let module_dir = module_dir.unwrap();
|
||||||
|
dbg!(&module_dir);
|
||||||
let path = module_dir.path();
|
let path = module_dir.path();
|
||||||
if !path.is_dir() {
|
if !path.is_dir() {
|
||||||
panic!("found unexpected file {}", path.to_string_lossy());
|
panic!("found unexpected file {}", path.to_string_lossy());
|
||||||
|
@ -28,6 +29,7 @@ fn main() {
|
||||||
let mut workflows = vec![];
|
let mut workflows = vec![];
|
||||||
|
|
||||||
for workflow_file in std::fs::read_dir(&path).unwrap() {
|
for workflow_file in std::fs::read_dir(&path).unwrap() {
|
||||||
|
dbg!(&workflow_file);
|
||||||
let workflow_file = workflow_file.unwrap();
|
let workflow_file = workflow_file.unwrap();
|
||||||
let path = workflow_file.path();
|
let path = workflow_file.path();
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use icepick_workflow::{InvocableOperation, OperationResult, Workflow, StringMap};
|
use icepick_workflow::{Input, InvocableOperation, OperationResult, StringMap, Workflow};
|
||||||
use keyfork_derive_util::{request::DerivationAlgorithm, DerivationPath};
|
use keyfork_derive_util::{request::DerivationAlgorithm, DerivationPath};
|
||||||
use keyfork_shard::{openpgp::OpenPGP, Format};
|
use keyfork_shard::{openpgp::OpenPGP, Format};
|
||||||
use miniquorum::{Payload, PayloadVerification};
|
use miniquorum::{Payload, PayloadVerification};
|
||||||
|
@ -91,31 +91,33 @@ impl InvocableOperation for CLIOperation {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_command(workflow: &Workflow) -> clap::Command {
|
pub fn generate_command(workflow: &Workflow) -> clap::Command {
|
||||||
let mut command = clap::Command::new(&workflow.name).arg(clap::arg!(
|
let mut command = clap::Command::new(&workflow.name).about(&workflow.description);
|
||||||
--"input-file" [FILE]
|
// NOTE: all required inputs are still marked as .required(false) since they could be included
|
||||||
"A file containing any inputs not passed on the command line"
|
// in the `--input-file` argument.
|
||||||
));
|
for input in workflow.inputs.iter() {
|
||||||
for input in &workflow.inputs {
|
for arg in input.identifiers() {
|
||||||
// can also be included in the JSON file, so we won't mark this as required.
|
let arg = clap::Arg::new(arg)
|
||||||
let arg = clap::Arg::new(input)
|
.required(false)
|
||||||
.required(false)
|
.help(&input.description)
|
||||||
.long(input.replace('_', "-"))
|
.long(arg.replace('_', "-"))
|
||||||
.value_name(input.to_uppercase());
|
.value_name(arg.to_uppercase())
|
||||||
command = command.arg(arg);
|
.conflicts_with_all(
|
||||||
|
input
|
||||||
|
.identifiers()
|
||||||
|
.filter(|name| *name != arg)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
command = command.arg(arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for input in &workflow.optional_inputs {
|
command.arg(clap::arg!(
|
||||||
let arg = clap::Arg::new(input)
|
--"input-file" [FILE]
|
||||||
.required(false)
|
"A file containing any inputs not passed on the command line"
|
||||||
.long(input.replace('_', "-"))
|
))
|
||||||
.value_name(input.to_uppercase());
|
|
||||||
command = command.arg(arg);
|
|
||||||
}
|
|
||||||
command
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_inputs<T: AsRef<str> + Into<String> + std::fmt::Display>(
|
fn load_inputs<'a>(
|
||||||
inputs: impl IntoIterator<Item = T>,
|
inputs: impl IntoIterator<Item = &'a Input>,
|
||||||
optional_inputs: impl IntoIterator<Item = T>,
|
|
||||||
matches: &clap::ArgMatches,
|
matches: &clap::ArgMatches,
|
||||||
) -> StringMap {
|
) -> StringMap {
|
||||||
let mut map = StringMap::default();
|
let mut map = StringMap::default();
|
||||||
|
@ -124,33 +126,25 @@ fn load_inputs<T: AsRef<str> + Into<String> + std::fmt::Display>(
|
||||||
.and_then(|p| std::fs::File::open(p).ok())
|
.and_then(|p| std::fs::File::open(p).ok())
|
||||||
.and_then(|f| serde_json::from_reader(f).ok());
|
.and_then(|f| serde_json::from_reader(f).ok());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
match matches.get_one::<String>(input.as_ref()) {
|
let identifier = &input.name;
|
||||||
|
match input
|
||||||
|
.identifiers()
|
||||||
|
.filter_map(|name| matches.get_one::<String>(name))
|
||||||
|
.next()
|
||||||
|
{
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
map.insert(input.into(), value.clone());
|
map.insert(identifier.clone(), value.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if let Some(value) = input_file.as_ref().and_then(|f| f.get(input.as_ref())) {
|
if let Some(value) = input_file.as_ref().and_then(|f| f.get(identifier)) {
|
||||||
map.insert(input.into(), value.clone());
|
map.insert(identifier.clone(), value.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("Required workflow input was not found: {input}");
|
if input.is_required() {
|
||||||
}
|
panic!("Required workflow input was not found: {identifier}");
|
||||||
|
|
||||||
for input in optional_inputs {
|
|
||||||
match matches.get_one::<String>(input.as_ref()) {
|
|
||||||
Some(value) => {
|
|
||||||
map.insert(input.into(), value.clone());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Some(value) = input_file.as_ref().and_then(|f| f.get(input.as_ref())) {
|
|
||||||
map.insert(input.into(), value.clone());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,13 +182,10 @@ pub fn parse_quorum_file(
|
||||||
let threshold = threshold.unwrap_or(u8::try_from(certs.len()).expect("too many certs!"));
|
let threshold = threshold.unwrap_or(u8::try_from(certs.len()).expect("too many certs!"));
|
||||||
let policy = match purpose {
|
let policy = match purpose {
|
||||||
Purpose::AddSignature => {
|
Purpose::AddSignature => {
|
||||||
// All signatures must be valid, but we don't require a minimum.
|
// All signatures must be valid, but we don't require a minimum.
|
||||||
PayloadVerification::new().with_threshold(0)
|
PayloadVerification::new().with_threshold(0)
|
||||||
}
|
}
|
||||||
Purpose::RunQuorum => {
|
Purpose::RunQuorum => PayloadVerification::new().with_threshold(threshold),
|
||||||
PayloadVerification::new().with_threshold(threshold)
|
|
||||||
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
payload.verify_signatures(&certs, &policy, None).unwrap();
|
payload.verify_signatures(&certs, &policy, None).unwrap();
|
||||||
|
|
||||||
|
@ -210,20 +201,19 @@ pub fn parse_quorum_with_shardfile(
|
||||||
let payload: Payload = serde_json::from_reader(payload_file).unwrap();
|
let payload: Payload = serde_json::from_reader(payload_file).unwrap();
|
||||||
|
|
||||||
let opgp = OpenPGP;
|
let opgp = OpenPGP;
|
||||||
let (threshold, certs) = opgp.decrypt_metadata_from_file(
|
let (threshold, certs) = opgp
|
||||||
None::<&std::path::Path>,
|
.decrypt_metadata_from_file(
|
||||||
std::fs::File::open(shardfile_path).unwrap(),
|
None::<&std::path::Path>,
|
||||||
keyfork_prompt::default_handler().unwrap(),
|
std::fs::File::open(shardfile_path).unwrap(),
|
||||||
).unwrap();
|
keyfork_prompt::default_handler().unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let policy = match purpose {
|
let policy = match purpose {
|
||||||
Purpose::AddSignature => {
|
Purpose::AddSignature => {
|
||||||
// All signatures must be valid, but we don't require a minimum.
|
// All signatures must be valid, but we don't require a minimum.
|
||||||
PayloadVerification::new().with_threshold(0)
|
PayloadVerification::new().with_threshold(0)
|
||||||
}
|
}
|
||||||
Purpose::RunQuorum => {
|
Purpose::RunQuorum => PayloadVerification::new().with_threshold(threshold),
|
||||||
PayloadVerification::new().with_threshold(threshold)
|
|
||||||
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
payload.verify_signatures(&certs, &policy, None).unwrap();
|
payload.verify_signatures(&certs, &policy, None).unwrap();
|
||||||
|
@ -251,7 +241,7 @@ pub fn handle(
|
||||||
modules: Commands,
|
modules: Commands,
|
||||||
config: &[ModuleConfig],
|
config: &[ModuleConfig],
|
||||||
) {
|
) {
|
||||||
let inputs = load_inputs(&workflow.inputs, &workflow.optional_inputs, matches);
|
let inputs = load_inputs(&workflow.inputs, matches);
|
||||||
let data: StringMap<Value> = inputs
|
let data: StringMap<Value> = inputs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| (k, Value::String(v)))
|
.map(|(k, v)| (k, Value::String(v)))
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
name: generate-address
|
name: generate-address
|
||||||
|
description: |-
|
||||||
|
Generate an address on a given Cosmos-based blockchain.
|
||||||
inputs:
|
inputs:
|
||||||
- chain_name
|
- name: chain_name
|
||||||
optional_inputs:
|
description: >-
|
||||||
- account
|
The name of the Cosmos chain you'd like to generate an address for.
|
||||||
|
- name: account
|
||||||
|
description: >-
|
||||||
|
The account to use, if not the default account.
|
||||||
|
optional: true
|
||||||
step:
|
step:
|
||||||
- type: cosmos-get-chain-info
|
- type: cosmos-get-chain-info
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -1,12 +1,27 @@
|
||||||
name: stake
|
name: stake
|
||||||
|
description: |-
|
||||||
|
Stake coins on the provided chain.
|
||||||
inputs:
|
inputs:
|
||||||
- delegate_address
|
- name: delegate_address
|
||||||
- validator_address
|
description: >-
|
||||||
- chain_name
|
Address holding the coins to be staked to a validator.
|
||||||
- asset_name
|
- name: validator_address
|
||||||
- asset_amount
|
description: >-
|
||||||
optional_inputs:
|
Address of the validator operator.
|
||||||
- gas_factor
|
- name: chain_name
|
||||||
|
description: >-
|
||||||
|
The name of the Cosmos-based chain.
|
||||||
|
- name: asset_name
|
||||||
|
description: >-
|
||||||
|
The name of the asset to stake.
|
||||||
|
- name: asset_amount
|
||||||
|
description: >-
|
||||||
|
The amount of the asset to stake.
|
||||||
|
- name: gas_factor
|
||||||
|
description: >-
|
||||||
|
An amount to multiply the required gas by; necessary if a chain requires
|
||||||
|
more gas for a specific operation.
|
||||||
|
optional: true
|
||||||
step:
|
step:
|
||||||
- type: cosmos-get-chain-info
|
- type: cosmos-get-chain-info
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
name: withdraw-rewards
|
name: withdraw-rewards
|
||||||
|
description: |-
|
||||||
|
Withdraw rewards gained from staking to a validator.
|
||||||
inputs:
|
inputs:
|
||||||
- delegate_address
|
- name: delegate_address
|
||||||
- validator_address
|
description: >-
|
||||||
- chain_name
|
The owner of the staked coins; also, the recipient of rewards.
|
||||||
optional_inputs:
|
- name: validator_address
|
||||||
- gas_factor
|
description: >-
|
||||||
|
The validator from whom coins are staked.
|
||||||
|
- name: chain_name
|
||||||
|
description: >-
|
||||||
|
The name of the Cosmos-based chain.
|
||||||
|
- name: gas_factor
|
||||||
|
description: >-
|
||||||
|
An amount to multiply the required gas by; necessary if a chain requires
|
||||||
|
more gas for a specific operation.
|
||||||
|
optional: true
|
||||||
step:
|
step:
|
||||||
- type: cosmos-get-chain-info
|
- type: cosmos-get-chain-info
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -1,12 +1,30 @@
|
||||||
name: withdraw
|
name: withdraw
|
||||||
|
description: |-
|
||||||
|
Withdraw staked coins from a validator.
|
||||||
|
|
||||||
|
Staked coins may be held for an unbonding period, depending on the chain upon
|
||||||
|
which they are staked.
|
||||||
inputs:
|
inputs:
|
||||||
- delegate_address
|
- name: delegate_address
|
||||||
- validator_address
|
description: >-
|
||||||
- chain_name
|
The owner of the staked coins.
|
||||||
- asset_name
|
- name: validator_address
|
||||||
- asset_amount
|
description: >-
|
||||||
optional_inputs:
|
The validator from whom coins are staked.
|
||||||
- gas_factor
|
- name: chain_name
|
||||||
|
description: >-
|
||||||
|
The name of the Cosmos-based chain.
|
||||||
|
- name: asset_name
|
||||||
|
description: >-
|
||||||
|
The name of the asset to withdraw.
|
||||||
|
- name: asset_amount
|
||||||
|
description: >-
|
||||||
|
The amount of the asset to withdraw.
|
||||||
|
- name: gas_factor
|
||||||
|
description: >-
|
||||||
|
An amount to multiply the required gas by; necessary if a chain requires
|
||||||
|
more gas for a specific operation.
|
||||||
|
optional: true
|
||||||
step:
|
step:
|
||||||
- type: cosmos-get-chain-info
|
- type: cosmos-get-chain-info
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
name: generate-address
|
name: generate-address
|
||||||
optional_inputs:
|
description: |-
|
||||||
- account
|
Generate a Solana address.
|
||||||
|
inputs:
|
||||||
|
- name: account
|
||||||
|
description: >-
|
||||||
|
The account to use, if not the default account.
|
||||||
|
optional: true
|
||||||
step:
|
step:
|
||||||
- type: sol-generate-wallet
|
- type: sol-generate-wallet
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
name: transfer-token
|
name: transfer-token
|
||||||
|
description: |-
|
||||||
|
Transfer SPL tokens held on the Solana blockchain.
|
||||||
inputs:
|
inputs:
|
||||||
- from_address
|
- name: from_address
|
||||||
- to_address
|
description: >-
|
||||||
- token_name
|
The address from which to send tokens.
|
||||||
- token_amount
|
- name: to_address
|
||||||
|
description: >-
|
||||||
|
The address to send coins to.
|
||||||
|
- name: token_name
|
||||||
|
description: >-
|
||||||
|
The name of the token to transfer.
|
||||||
|
- name: token_amount
|
||||||
|
description: >-
|
||||||
|
The amount of the token to transfer.
|
||||||
step:
|
step:
|
||||||
- type: sol-get-token-info
|
- type: sol-get-token-info
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
name: generate-address
|
name: generate-address
|
||||||
optional_inputs:
|
description: |-
|
||||||
- account
|
Generate a Spacemesh address
|
||||||
- cluster
|
inputs:
|
||||||
|
- name: account
|
||||||
|
description: >-
|
||||||
|
The account to use, if not the default account.
|
||||||
|
optional: true
|
||||||
|
- name: cluster
|
||||||
|
description: >-
|
||||||
|
The Spacemesh cluster to use, if not the mainnet.
|
||||||
|
optional: true
|
||||||
step:
|
step:
|
||||||
- type: spacemesh-generate-wallet
|
- type: spacemesh-generate-wallet
|
||||||
inputs:
|
inputs:
|
||||||
|
|
214
icepick.toml
214
icepick.toml
|
@ -3,225 +3,11 @@ name = "sol"
|
||||||
derivation_prefix = "m/44'/501'/0'"
|
derivation_prefix = "m/44'/501'/0'"
|
||||||
algorithm = "Ed25519"
|
algorithm = "Ed25519"
|
||||||
|
|
||||||
# NOTE: To get a nonce address, the `generate-nonce-account` workflow should be
|
|
||||||
# run. It is the only workflow that uses a blockhash, which is why a
|
|
||||||
# `broadcast-with-blockhash` or similar is not, and should not be, implemented.
|
|
||||||
[[module.workflow]]
|
|
||||||
name = "broadcast"
|
|
||||||
inputs = ["nonce_address", "cluster"]
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-get-nonce-account-data"
|
|
||||||
inputs = { nonce_address = "nonce_address", cluster = "cluster" }
|
|
||||||
outputs = { authority = "nonce_authority", durable_nonce = "nonce" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-save-file"
|
|
||||||
values = { filename = "nonce.json" }
|
|
||||||
inputs = { nonce_authority = "nonce_authority", nonce_data = "nonce", nonce_address = "nonce_address" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-load-file"
|
|
||||||
values = { filename = "transaction.json" }
|
|
||||||
outputs = { transaction = "transaction" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-broadcast"
|
|
||||||
inputs = { cluster = "cluster", transaction = "transaction" }
|
|
||||||
outputs = { status = "status", url = "url", error = "error" }
|
|
||||||
|
|
||||||
[[module.workflow]]
|
|
||||||
name = "generate-nonce-account"
|
|
||||||
inputs = ["cluster", "authorization_address"]
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-generate-wallet"
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-get-wallet-address"
|
|
||||||
outputs = { pubkey = "wallet_pubkey" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-await-funds"
|
|
||||||
inputs = { address = "wallet_pubkey", cluster = "cluster" }
|
|
||||||
# enough to cover two signatures and the 1_500_000 approx. rent fee
|
|
||||||
values = { lamports = "1510000" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-get-blockhash"
|
|
||||||
inputs = { cluster = "cluster" }
|
|
||||||
outputs = { blockhash = "blockhash" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-create-nonce-account-and-signing-key"
|
|
||||||
|
|
||||||
[module.workflow.step.inputs]
|
|
||||||
from_address = "wallet_pubkey"
|
|
||||||
authorization_address = "authorization_address"
|
|
||||||
|
|
||||||
[module.workflow.step.outputs]
|
|
||||||
transaction = "instructions"
|
|
||||||
nonce_pubkey = "nonce_pubkey"
|
|
||||||
nonce_privkey = "private_keys"
|
|
||||||
derivation_accounts = "derivation_accounts"
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-compile"
|
|
||||||
|
|
||||||
[module.workflow.step.inputs]
|
|
||||||
instructions = "instructions"
|
|
||||||
derivation_accounts = "derivation_accounts"
|
|
||||||
blockhash = "blockhash"
|
|
||||||
|
|
||||||
[module.workflow.step.outputs]
|
|
||||||
transaction = "unsigned_transaction"
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-sign"
|
|
||||||
|
|
||||||
[module.workflow.step.inputs]
|
|
||||||
blockhash = "blockhash"
|
|
||||||
signing_keys = "private_keys"
|
|
||||||
transaction = "unsigned_transaction"
|
|
||||||
|
|
||||||
[module.workflow.step.outputs]
|
|
||||||
transaction = "signed_transaction"
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-broadcast"
|
|
||||||
inputs = { cluster = "cluster", transaction = "signed_transaction" }
|
|
||||||
outputs = { status = "status", url = "url", error = "error" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-cat"
|
|
||||||
inputs = { status = "status", url = "url", nonce_account = "nonce_pubkey", error = "error" }
|
|
||||||
outputs = { status = "status", url = "url", nonce_account = "nonce_account", error = "error" }
|
|
||||||
|
|
||||||
[[module.workflow]]
|
|
||||||
# Transfer SOL from one address to another.
|
|
||||||
name = "transfer"
|
|
||||||
inputs = ["to_address", "from_address", "amount"]
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-load-file"
|
|
||||||
values = { filename = "nonce.json" }
|
|
||||||
outputs = { nonce_authority = "nonce_authority", nonce_data = "nonce_data", nonce_address = "nonce_address" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-transfer"
|
|
||||||
inputs = { from_address = "from_address", to_address = "to_address", amount = "amount" }
|
|
||||||
outputs = { instructions = "instructions", derivation_accounts = "derivation_accounts" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-compile"
|
|
||||||
|
|
||||||
[module.workflow.step.inputs]
|
|
||||||
instructions = "instructions"
|
|
||||||
derivation_accounts = "derivation_accounts"
|
|
||||||
nonce_address = "nonce_address"
|
|
||||||
nonce_authority = "nonce_authority"
|
|
||||||
nonce_data = "nonce_data"
|
|
||||||
|
|
||||||
[module.workflow.step.outputs]
|
|
||||||
transaction = "unsigned_transaction"
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "sol-sign"
|
|
||||||
|
|
||||||
inputs = { blockhash = "nonce_data", transaction = "unsigned_transaction" }
|
|
||||||
outputs = { transaction = "signed_transaction" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-save-file"
|
|
||||||
|
|
||||||
values = { filename = "transaction.json" }
|
|
||||||
inputs = { transaction = "signed_transaction" }
|
|
||||||
|
|
||||||
[[module]]
|
[[module]]
|
||||||
name = "cosmos"
|
name = "cosmos"
|
||||||
derivation_prefix = "m/44'/118'/0'"
|
derivation_prefix = "m/44'/118'/0'"
|
||||||
algorithm = "Secp256k1"
|
algorithm = "Secp256k1"
|
||||||
|
|
||||||
[[module.workflow]]
|
|
||||||
name = "transfer"
|
|
||||||
inputs = ["from_address", "to_address", "asset_name", "chain_name", "asset_amount"]
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
# NOTE: chain_name can't be discoverable by filtering from asset_name, since
|
|
||||||
# some asset devnets reuse the name. There's no difference between KYVE on Kyve
|
|
||||||
# or Korellia (devnet).
|
|
||||||
type = "cosmos-get-chain-info"
|
|
||||||
inputs = { chain_name = "chain_name" }
|
|
||||||
outputs = { blockchain_config = "blockchain_config" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-load-file"
|
|
||||||
values = { filename = "account_info.json" }
|
|
||||||
outputs = { account_number = "account_number", sequence_number = "sequence_number" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "cosmos-transfer"
|
|
||||||
|
|
||||||
[module.workflow.step.inputs]
|
|
||||||
from_address = "from_address"
|
|
||||||
to_address = "to_address"
|
|
||||||
amount = "asset_amount"
|
|
||||||
denom = "asset_name"
|
|
||||||
blockchain_config = "blockchain_config"
|
|
||||||
|
|
||||||
[module.workflow.step.outputs]
|
|
||||||
fee = "fee"
|
|
||||||
tx_messages = "tx_messages"
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "cosmos-sign"
|
|
||||||
|
|
||||||
[module.workflow.step.inputs]
|
|
||||||
fee = "fee"
|
|
||||||
tx_messages = "tx_messages"
|
|
||||||
account_number = "account_number"
|
|
||||||
sequence_number = "sequence_number"
|
|
||||||
blockchain_config = "blockchain_config"
|
|
||||||
|
|
||||||
[module.workflow.step.outputs]
|
|
||||||
transaction = "signed_transaction"
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-save-file"
|
|
||||||
values = { filename = "transaction.json" }
|
|
||||||
inputs = { transaction = "signed_transaction" }
|
|
||||||
|
|
||||||
[[module.workflow]]
|
|
||||||
name = "broadcast"
|
|
||||||
# NOTE: For the purpose of Cosmos, the nonce is a direct part of the signer's
|
|
||||||
# account.
|
|
||||||
inputs = ["nonce_address", "chain_name"]
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "cosmos-get-chain-info"
|
|
||||||
inputs = { chain_name = "chain_name" }
|
|
||||||
outputs = { blockchain_config = "blockchain_config" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "cosmos-get-account-data"
|
|
||||||
inputs = { account_id = "nonce_address", blockchain_config = "blockchain_config" }
|
|
||||||
outputs = { account_number = "account_number", sequence_number = "sequence_number" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-save-file"
|
|
||||||
values = { filename = "account_info.json" }
|
|
||||||
inputs = { account_number = "account_number", sequence_number = "sequence_number" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "internal-load-file"
|
|
||||||
values = { filename = "transaction.json" }
|
|
||||||
outputs = { transaction = "transaction" }
|
|
||||||
|
|
||||||
[[module.workflow.step]]
|
|
||||||
type = "cosmos-broadcast"
|
|
||||||
inputs = { blockchain_config = "blockchain_config", transaction = "transaction" }
|
|
||||||
outputs = { status = "status", url = "url", error = "error", error_code = "error_code" }
|
|
||||||
|
|
||||||
[[module]]
|
[[module]]
|
||||||
name = "spacemesh"
|
name = "spacemesh"
|
||||||
derivation_prefix = "m/44'/540'/0'/0'"
|
derivation_prefix = "m/44'/540'/0'/0'"
|
||||||
|
|
Loading…
Reference in New Issue