Passa al contenuto principale

Guida rapida

Da zero a una transazione inviata. Questa pagina utilizza l'SDK TypeScript (@qorechain/sdk); brevi snippet di connessione e lettura per Python, Go e Rust si trovano alla fine.

1. Connessione​

createClient() risolve una rete e compone i client di lettura, un helper per le commissioni e un punto di ingresso pigro per la firma. Per impostazione predefinita punta alla testnet pubblica (qorechain-diana). Gli endpoint predefiniti puntano a localhost, quindi passa endpoints per comunicare con un nodo reale. Gli endpoint pubblici sono elencati nel riferimento di rete.

import { createClient } from "@qorechain/sdk";

// Testnet (chain id "qorechain-diana"), default localhost endpoints.
const client = createClient();

// Point at the public testnet by overriding endpoints.
const remote = createClient({
endpoints: {
rest: "https://api-testnet.qore.host", // Native REST (LCD)
rpc: "https://rpc-testnet.qore.host", // consensus RPC (for signing)
evmRpc: "https://evm-testnet.qore.host", // EVM JSON-RPC (eth_*)
},
});

La mainnet (chain id qorechain-vladi) è attiva. Selezionala e sostituisci i valori predefiniti localhost con gli endpoint pubblici (o con il tuo nodo):

const main = createClient({
network: "mainnet",
endpoints: {
rest: "https://api.qore.host",
rpc: "https://rpc.qore.host",
evmRpc: "https://evm.qore.host",
},
});

2. Derivare un account​

Una singola mnemonica deriva account native (qor1…), EVM (0x…) e SVM (base58) tramite percorsi di derivazione indipendenti.

import {
generateMnemonic,
deriveNativeAccount,
} from "@qorechain/sdk";

const mnemonic = generateMnemonic(); // 12 words (pass 256 for 24 words)

const native = await deriveNativeAccount(mnemonic);
console.log(native.address); // "qor1..." (Native secp256k1, coin type 118)

A partire dalla 0.6.0 puoi invece derivare un account unificato eth-native — una sola chiave eth_secp256k1 rappresentata come tutti e tre gli indirizzi (qor1…, 0x…, base58 SVM) con un unico saldo condiviso:

import { deriveUnifiedAccount } from "@qorechain/sdk";

const unified = await deriveUnifiedAccount(mnemonic);
console.log(unified.cosmos); // "qor1..."
console.log(unified.evm); // "0x..."
console.log(unified.svm); // base58 (same 20 bytes + 12 zero bytes)

Vedi Account e firma PQC per la derivazione EVM/SVM, gli account unificati e la tabella di derivazione completa.

3. Leggere un saldo​

// Native bank balances over REST.
const balances = await client.rest.getAllBalances(native.address);

// Any REST route works through the typed escape hatch, for example the burn
// statistics.
const burn = await client.rest.getBurnStats();

client.qor (le chiamate JSON-RPC qor_ tipizzate) non è utilizzabile sugli endpoint pubblici: nessuna build del nodo rilasciata serve quel namespace, quindi ogni chiamata restituisce -32601 (metodo non trovato). Leggi invece tramite REST. Vedi il namespace qor_.

4. Inviare un trasferimento QOR​

Su mainnet e testnet ogni transazione del percorso Native deve portare la firma ibrida (secp256k1 classica più ML-DSA-87), e la chiave ML-DSA-87 dell'account deve essere registrata prima on-chain. La registrazione è esplicita: non esiste alcuna registrazione automatica alla prima transazione. Un semplice tx.bankSend (solo firma classica) viene rifiutato dalle reti live. I due passaggi seguenti richiedono SDK 0.8.3 o successivo (derivePqcCanonical; 0.8.1 o successivo per gli invii ibridi in generale) e un account con fondi:

npm i @qorechain/sdk @cosmjs/stargate

4a. Registrare la tua chiave post-quantistica (una sola volta)​

La registrazione è firmata in modo classico ed esente dal requisito ibrido, così un nuovo account può avviare la sua prima chiave. L'account paga la commissione: la chiave da 2.592 byte richiede un gas limit di circa 600.000.

import {
createClient,
deriveNativeAccount,
directSignerFromPrivateKey,
derivePqcCanonical,
ensurePqcRegistered,
} from "@qorechain/sdk";

const REST = "https://api-testnet.qore.host";
const RPC = "https://rpc-testnet.qore.host";

const client = createClient({ endpoints: { rest: REST, rpc: RPC } });

const account = await deriveNativeAccount(mnemonic);
const signer = await directSignerFromPrivateKey(account.privateKey, "qor");
const tx = await client.connectTx(signer);

// The address-bound ML-DSA-87 key, recoverable from { address, mnemonic }.
const pqcKeypair = derivePqcCanonical(account.address, mnemonic);

// Read the status over REST (the default status source needs `qor_`).
const { found } = await client.rest.get<{ found: boolean }>(
`/qorechain/pqc/v1/account/${account.address}`,
);

const res = await ensurePqcRegistered(tx, {
pqcKeypair,
ecdsaPubkey: account.publicKey,
status: { registered: found }, // skips the transaction when already registered
fee: { amount: [{ denom: "uqor", amount: "60000" }], gas: "600000" },
});
console.log(res.alreadyRegistered ? "already registered" : res.txHash);

4b. Inviare con una firma ibrida​

signAndBroadcastHybrid costruisce, firma e trasmette. Passa rest in modo che l'SDK possa chiedere alla rete quale forma di sign-bytes verifica (vedi Quale forma di sign-bytes?). Usa toBase("1.5") per convertire QOR in uqor base. Il prezzo minimo del gas della rete è 0,1 uqor per unità di gas, quindi un gas limit di 400.000 richiede una commissione di almeno 40.000 uqor.

import { StargateClient } from "@cosmjs/stargate";
import {
signAndBroadcastHybrid,
qorechainRegistry,
MSG_SEND_TYPE_URL,
toBase,
} from "@qorechain/sdk";

const transport = await StargateClient.connect(RPC);
const info = await transport.getSequence(account.address); // { accountNumber, sequence }

const result = await signAndBroadcastHybrid({
registry: qorechainRegistry(),
signer,
pqcKeypair,
messages: [
{
typeUrl: MSG_SEND_TYPE_URL,
value: {
fromAddress: account.address,
toAddress: "qor1recipientaddress...",
amount: [{ denom: "uqor", amount: toBase("1.5") }],
},
},
],
fee: { amount: [{ denom: "uqor", amount: "40000" }], gas: "400000" },
chainId: client.network.chainId,
accountNumber: info.accountNumber,
sequence: info.sequence,
rest: REST,
transport,
});

console.log(result.transactionHash);

toBase("1.5") restituisce "1500000" (QOR ha 10^6 unità base uqor).

Account unificati

Per un account unificato eth-native (deriveUnifiedAccount), usa invece EthNativeSigner; gli esempi di registrazione e invio si trovano in Account e firma PQC.

Gli invii classici funzionano solo su nodi locali e di sviluppo

Il percorso classico client.connectTx(signer) più tx.bankSend(...) esiste ancora, ed è quello che ensurePqcRegistered usa per l'unica transazione di registrazione. Su un nodo che non richiede l'estensione ibrida (un nodo di sviluppo locale) invia anche trasferimenti ordinari. Le reti pubbliche lo rifiutano.

Altri linguaggi: connessione e lettura​

Questi rispecchiano gli stessi preset di rete e la stessa superficie di lettura. Usano gli endpoint della testnet pubblica; per la mainnet passa "mainnet" e gli URL della mainnet.

Python​

from qorsdk import create_client

client = create_client(
network="testnet",
endpoints={
"rest": "https://api-testnet.qore.host",
"rpc": "https://rpc-testnet.qore.host",
"evm_rpc": "https://evm-testnet.qore.host",
},
)
print(client.network.chain_id) # "qorechain-diana"

balances = client.rest.get_all_balances("qor1...")
burn = client.rest.get_burn_stats()
client.close()

Go​

import (
"fmt"

"github.com/qorechain/qorechain-sdk/packages/go/qorechain/client"
)

c, err := client.CreateClient(client.Options{
Network: "testnet",
Endpoints: client.EndpointOverrides{
REST: "https://api-testnet.qore.host",
RPC: "https://rpc-testnet.qore.host",
EVMRPC: "https://evm-testnet.qore.host",
},
})
if err != nil {
panic(err)
}
fmt.Println(c.Network.ChainID) // qorechain-diana

balances, err := c.REST.GetAllBalances("qor1...")
burn, err := c.REST.GetBurnStats()

Rust​

use qorechain::ClientBuilder;

#[tokio::main]
async fn main() -> qorechain::Result<()> {
let client = ClientBuilder::new()
.network("testnet")
.rest("https://api-testnet.qore.host")
.rpc("https://rpc-testnet.qore.host")
.evm_rpc("https://evm-testnet.qore.host")
.build()?;
let balances = client.rest.get_all_balances("qor1...").await?;
let burn = client.rest.get_burn_stats().await?;
let _ = (balances, burn);
Ok(())
}

Prossimi passi​