Bir akıllı sözleşme işlevini, arkasındaki veriyi görmeden bir kimlik belgesine nasıl bağlarsınız
Bu rehber bir Solidity işlevini tek bir modifier ile bir Solidus kimlik belgesine bağlar ve aynı denetimi TypeScript'ten de gösterir. Sözleşmeniz kimlik belgesini hiçbir zaman almaz.
Ne kuruyorsunuz
Bir Solidity işlevine tek bir modifier ekliyorsunuz. Bundan sonra o işlevi yalnızca geçerli bir Solidus kimlik belgesine sahip bir adres çağırabilir. Sözleşmeniz kimlik belgesini hiçbir zaman almaz. Solidus Bridge'in sizin zincirinizde tuttuğu küçük bir kaydı okur: belgeyi verenin hash'i, belge türünün hash'i, sahip anahtarı, bir durum, bir son kullanma zamanı ve kaydın geldiği Solidus blok yüksekliği. Denetim başarısız olduğunda çağrı, nedenini söyleyen bir sayıyla geri alınır (revert). Canlı rotalar Sepolia, Fuji ve Arc test ağları için bir ayna, bir kayıt defteri ve bu örneği listeler. O kaydın oraya nasıl geldiğini görmek için kimlik belgesi durumu köprüsü nedir sayfasını okuyun.
Kapıyı ekleyin
SolidusGated sözleşmesinden miras alın ve işlevin üzerine onlyCredentialed koyun. Aşağıdaki, başlık yorumu çıkarılmış hâliyle SolidusGated.sol içindeki temel sözleşmedir:
abstract contract SolidusGated {
ISolidusCredentialMirror public immutable mirror;
constructor(ISolidusCredentialMirror mirror_) {
mirror = mirror_;
}
/// Reverts `SolidusGate.CredentialRequired` with the reason, so the caller learns WHY.
modifier onlyCredentialed(bytes32 credentialTypeHash, bytes32 issuerDidHash, uint64 maxAge) {
SolidusGate.requireCredential(
mirror, SolidusGate.holderOf(msg.sender), credentialTypeHash, issuerDidHash, maxAge
);
_;
}
}
Bu, en küçük gerçek kullanımdır: ExampleGatedVault.sol. Yalnızca bir KycL2 belgesine sahip olan para yatırabilir:
pragma solidity 0.8.28;
import {ISolidusCredentialMirror} from "../interfaces/ISolidusCredentialMirror.sol";
import {SolidusGated} from "../SolidusGated.sol";
contract ExampleGatedVault is SolidusGated {
bytes32 public constant KYC_L2 = keccak256("KycL2");
uint64 public constant MAX_AGE = 1 days;
bytes32 public immutable issuerDidHash;
mapping(address => uint256) public balanceOf;
error InsufficientBalance(uint256 have, uint256 want);
error TransferFailed();
constructor(ISolidusCredentialMirror mirror_, bytes32 issuerDidHash_) SolidusGated(mirror_) {
issuerDidHash = issuerDidHash_;
}
function deposit() external payable onlyCredentialed(KYC_L2, issuerDidHash, MAX_AGE) {
balanceOf[msg.sender] += msg.value;
}
function withdraw(uint256 amount) external {
uint256 balance = balanceOf[msg.sender];
if (amount > balance) revert InsufficientBalance(balance, amount);
balanceOf[msg.sender] = balance - amount;
(bool ok,) = msg.sender.call{value: amount}("");
if (!ok) revert TransferFailed();
}
}
Üç sözleşme SolidusGated.sol, lib/SolidusGate.sol ve examples/ExampleGatedVault.sol dosyalarıdır ve üçü de bridge-contracts deposunda src/ altındadır. Yukarıdaki import satırları bu düzene uyar.
Üç ayrıntı önemli:
- Argümanlar.
credentialTypeHashveissuerDidHashbelgeyi seçer.maxAgesaniye cinsindendir. Ayna sözleşmesinin Solidus'tan aldığı son kalp atışının en fazla ne kadar eski olabileceğini sınırlar. Belgenin yaşını sınırlamaz. - Çağıran. Modifier
msg.senderdeğerini denetler. Belge, çağrıyı yapan adrese aktarılmış olmalıdır. - Çıkış.
depositkapıdadır,withdrawdeğildir; bu bilinçli.withdrawkapıda olsaydı bir iptal ya da sessizleşen bir köprü kullanıcının parasını hapsedebilirdi. Kapıyı girişe koyun.
Nedeni okuyun
Başarısız bir denetim CredentialRequired(holder, credentialTypeHash, issuerDidHash, reason) ile geri alınır. Son alan, GateReason içinden bir uint8 değeridir. Denetimler bu sırayla çalışır ve bildirilen, ilk başarısızlıktır.
| neden | ad | anlamı |
|---|---|---|
| 0 | OK |
Denetim geçti. Bir geri almada bunu hiç görmezsiniz. |
| 1 | NO_EXPORT |
Ayna sözleşmesinde bu sahip, belge türü ve belgeyi veren için kayıt yok. |
| 2 | NOT_ACTIVE |
Kayıt var ama durumu etkin değil. Kodlayıcı iptal edilmiş, süresi dolmuş ve bağı kaldırılmış durumlarını tanımlar. |
| 3 | ISSUER_NOT_ACCREDITED |
Ayna sözleşmesi bu belge vereni yetkili olarak listelemiyor. |
| 4 | EXPIRED |
Kaydın bir son kullanma zamanı var ve geçti. 0 olan son kullanma zamanı, süresiz demektir. |
| 5 | STALE |
Hiç kalp atışı gelmedi ya da sonuncusu maxAge değerinden eski. |
Kod yorumu bu numaraların arayüzün parçası olduğunu ve hiçbir zaman yeniden numaralandırılmadığını söylüyor. STALE, sahip hakkında hiçbir şey söylemeyen tek nedendir. Köprü sessizleşmiştir ve sahip yalnızca bekleyebilir. Durum sayfası her zincir için kalp atışı yaşını gösterir.
Bir nedeni işlem göndermeden okuyabilirsiniz. Bu komut, Sepolia'da belgesi olmayan bir adresten yapılan para yatırmayı simüle eder (tek çağrı, 2026-10-08):
cast call 0x923f75C32F3e1556Ee516d44E89088454D9E27a8 "deposit()" \
--from 0x0000000000000000000000000000000000000001 \
--rpc-url https://ethereum-sepolia-rpc.publicnode.com
# Error: ... execution reverted, data: "0xa641a24e...0001"
İlk dört bayt olan 0xa641a24e, CredentialRequired seçicisidir. Son kelime 0001 değeridir: neden 1, NO_EXPORT. Zincir dışında @solidus-network/bridge paketi bir sayıyı gateReasonName ile ada çevirir. Geliştiriciler sayfası bunu gösterir.
Adresler nereden gelir
Ayna sözleşmesinin adresini kurucunuza (constructor) verin. SolidusGated onu bilinçli olarak immutable saklar: değiştirilebilir bir ayna, kılık değiştirmiş bir yükseltme yolu olurdu. Yerine geçen bir ayna sözleşmesini izlemek isterseniz çağrıyı yaptığınız yerde SolidusRegistry.mirrorOf(domain) okuyun. Alan (domain), hedef zincirin kendi alanıdır ve Sepolia, Fuji ve Arc'ta zincir kimliğine eşittir. Cevabı yalnızca kayıt defterinin sahibi değiştirebilir ve sahibi bir zaman kilididir (timelock). Sepolia'da asgari gecikmesi 172800 saniye, yani 48 saat olarak okunur.
Adresleri her zincir için listeleyen canlı /v1/routes yanıtından okuyun. 2026-10-08 tarihinde Sepolia, Fuji ve Arc aynı ayna adresini ve aynı kayıt defteri adresini kullanıyordu. Sepolia kayıt defterinde mirrorOf(11155111) o aynayı, mirrorOf(1) sıfır adresini döndürür. Her ayna kendi alanını doğruladığı özete bağlar; bu yüzden bir zincir için atılmış imza başka bir zincirde yeniden kullanılamaz. Hedef, imzalanan şeyin içindedir sayfası bunun nasıl olduğunu anlatır. Solana devnet bir ayna adresi listeler, kayıt defteri listelemez. Bu makale EVM kapısını kapsar.
Aynı kapıyı TypeScript'ten okuyun
@solidus-network/bridge paketi kapıyı sözleşmenin okuduğu gibi, aynı sırayla okur. Böylece bir arayüz, sahip geri alınan bir işlem için ödeme yapmadan önce bir reddi açıklayabilir. Kendi viem istemcinizi verirsiniz; paket kendi RPC adresiyle gelmez.
import { checkGate, credentialTypeHash, gateReasonName, holderFromEvmAddress } from '@solidus-network/bridge'
const result = await checkGate({
client: publicClient,
mirror: mirrorAddress,
holder: holderFromEvmAddress(account.address),
credentialTypeHash: credentialTypeHash('KycL2'),
issuerDidHash,
maxAge: 86_400n,
})
if (!result.ok) console.log(`cannot proceed: ${gateReasonName(result.reason)}`)
Sonuç ok, reason, exportId ve heartbeatAgeSecs alanlarını taşır. 0.2.0 sürümü 2026-10-08 tarihinde npm'deki en son sürümdü. maxAge sınırına yakın bir sonuç kesin değildir, çünkü sözleşme hedef zincirin blok zamanına göre ölçer; paket ise siz now vermedikçe makinenizin saatini kullanır.
Tek komutla görün
curl -sL https://bridge.solidus.network/v1/routes \
| jq '.chains[0] | {key, domain, contracts: {mirror: .contracts.mirror, registry: .contracts.registry}}'
{
"key": "sepolia",
"domain": 11155111,
"contracts": {
"mirror": "0x0a5a0d19206f436d67B7b87BF4c889d5b769517A",
"registry": "0x19aF92b387200827E0540f516FEd1468B09806A5"
}
}
2026-10-08 tarihinde çalıştırıldı. Tam yanıt her zinciri listeler; jq süzgeci birinin iki alanını tutar.
Okumaya devam edin
- Kimlik belgesi durumu köprüsü nedir ve başka bir zincirdeki sözleşmenin neden ona ihtiyacı olur
- Hedef, imzalanan şeyin içindedir; bu yüzden bir imza başka bir zincirde yeniden kullanılamaz
- Doğrulayıcıların bir durum mesajını nasıl imzaladığı ve bir ağ geçidinin onu başka bir zincire nasıl ilettiği
- Ayna sözleşmesini Solidity, TypeScript ve komut satırından okuyun