Smart Contract
Savitri Network fornisce un runtime nativo per smart contract con standard token integrati, governance e supporto oracle.
Runtime dei Contract
I contract vengono eseguiti in un ambiente isolato (sandbox) con:
- Misurazione del gas: Ogni operazione consuma gas per prevenire i loop infiniti
- Slot di storage: Archiviazione chiave-valore tramite indirizzi di slot con hash Keccak256
- Sistema di eventi: I contract emettono eventi per i consumatori esterni
- Monitoraggio della memoria: I limiti di memoria del runtime prevengono attacchi DoS
- Supporto all'aggiornamento: I contract possono essere aggiornati tramite governance
Standard Token
| Standard | Tipo | Equivalente | Descrizione |
|---|---|---|---|
| SAVITRI-20 | Fungibile | ERC-20 | Trasferimenti token, approvazioni, indennità |
| SAVITRI-721 | Non Fungibile (NFT) | ERC-721 | Proprietà token unici, trasferimenti, metadati |
| SAVITRI-1155 | Multi-Asset | ERC-1155 | Operazioni batch, fungibile/non fungibile misto |
Contract Integrati
Governance
Sistema di proposta e votazione on-chain:
- Crea proposte con titolo, descrizione e periodo di votazione
- Vota a favore/contro
- Esegui le proposte approvate
- Specializzazione delle proposte FL (Federated Learning)
Vedi Governance per i dettagli.
Oracle
Sistema di feed di dati esterni:
- Registra i provider oracle
- Richiedi e invia dati
- Verifica delle prove
- Validazione dello schema
Vedi Sistema Oracle per i dettagli.
Interazione con i Contract tramite SDK
Utilizzo di ContractClient
use savitri_sdk::{ContractClient, Wallet, RpcClient};
let wallet = Wallet::from_private_key_hex("your_key")?;
let contract = ContractClient::from_url_and_wallet("http://localhost:8545", wallet)?;
// Chiama una funzione del contract
let tx_hash = contract.call_contract(
&"contract_address".to_string(),
b"transfer",
&encoded_args,
Some(0),
).await?;
Utilizzo di TransactionBuilder
use savitri_sdk::TransactionBuilder;
let tx = TransactionBuilder::new()
.to("contract_address")
.data(call_data) // function selector + encoded args
.value(0)
.nonce(nonce)
.fee(5_000_000_000_000_000) // 0.005 SAVT contract fee
.build_and_sign(&wallet)?;
Modello di Storage
I contract utilizzano un modello di storage basato su slot simile a Ethereum:
- Slot 0-99: Riservati a
BaseContract(proprietario, metadati) - Slot 100+: Storage specifico del contract
Gli indirizzi degli slot vengono derivati tramite hash Keccak256 per prevenire collisioni:
balance_slot = keccak256(address || SLOT_BALANCES_BASE)
allowance_slot = keccak256(spender || keccak256(owner || SLOT_ALLOWANCES_BASE))
Tutti i valori sono memorizzati come array di 32 byte (little-endian per i tipi numerici).
Costi del Gas
| Operazione | Costo Gas | Commissione (SAVT) |
|---|---|---|
| Deploy contract | Variabile | 0.005 base |
| Chiamata contract | Variabile | 0.005 base |
| Scrittura storage (SSTORE) | 20.000 | Inclusa nel base |
| Lettura storage (SLOAD) | 200 | Inclusa nel base |
| Trasferimento token | ~50.000 | 0.005 |
| Mint NFT | ~80.000 | 0.005 |
| Voto governance | ~30.000 | 0.005 |
Deploy dei Contract
I contract vengono distribuiti tramite transazioni speciali con to = None e il bytecode del contract nel campo data:
let deploy_tx = TransactionBuilder::new()
// Nessun .to() -- indica il deploy del contract
.data(contract_bytecode)
.value(0)
.nonce(nonce)
.fee(5_000_000_000_000_000)
.build_and_sign(&wallet)?;