Skip to main content

Sui 交易所集成指南

本主题描述了如何将 SUI,Sui 网络的原生代币,集成到加密货币交易所。在不同交易所之间,实施集成的具体要求和流程可能有所不同。与其提供逐步指南,本主题提供了有关完成集成所需的主要任务的信息。在有关如何配置集成的指导之后,你还可以找到有关在 Sui 网络上进行质押的信息和代码示例。

配置 SUI 集成的要求

配置 SUI 集成的要求包括:

  • 一个 Sui 全节点。你可以运营自己的 Sui 全节点或使用节点操作员提供的全节点。
  • 运行 Sui 全节点的建议硬件要求:
    • CPU:8 个物理核心 / 16 个虚拟核心
    • RAM:128 GB
    • 存储(SSD):4 TB NVMe 驱动器

为获得最佳效果,请在 Linux 上运行 Sui 全节点。Sui 支持 Ubuntu 和 Debian 发行版。你也可以在 macOS 上运行全节点。

配置 Sui 全节点

你可以使用 Docker 或直接从 Sui GitHub 存储库的源代码设置和配置 Sui 全节点

设置 Sui 地址

Sui 地址无需链上初始化,如果与你的私钥对应,可以从地址支出。你可以通过使用 BLAKE2b(256 位输出)哈希函数对签名方案标志字节与公钥字节 flag || pubkey 进行哈希运算,来派生一个 32 字节的 Sui 地址。

目前,Sui 地址支持以下签名方案:纯 Ed25519、Secp256k1、Secp256r1 和多重签名。相应的标志字节分别为 0x00、0x01、0x02、0x03。

以下代码示例演示了如何在 Rust 中派生 Sui 地址:

let flag = 0x00; // 0x00 = ED25519, 0x01 = Secp256k1, 0x02 = Secp256r1, 0x03 = multiSig
// Hash the [flag, public key] bytearray using Blake2b
let mut hasher = DefaultHash::default();
hasher.update([flag]);
hasher.update(pk);
let arr = hasher.finalize();
let sui_address_string = hex::encode(arr);

显示地址

Sui 支持带有和不带有 0x 前缀的地址。Sui 建议在 API 调用和显示用户地址时始终包括 0x 前缀。

跟踪地址的余额变化

你可以通过在预定义的时间间隔调用 sui_getBalance 来跟踪余额变化。此调用返回地址的总余额。总余额包括任何币种或代币类型,但本文重点介绍 SUI。你可以在连续的 sui_getBalance 请求之间跟踪地址的总余额变化。

以下 bash 示例演示了如何使用 sui_getBalance 获取地址 0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3 的余额。如果你使用的网络不是 Devnet,请用适当的全节点 URL 替换 rpc 的值。

rpc="https://fullnode.devnet.sui.io:443"
address="0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3"
data="{\"jsonrpc\": \"2.0\", \"method\": \"sui_getBalance\", \"id\": 1, \"params\": [\"$address\"]}"
curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc

The response is a JSON object that includes the totalBalance for the address:

{
"jsonrpc":"2.0",
"result":{
"coinType":"0x2::sui::SUI",
"coinObjectCount":40,
"totalBalance":10000000000,
"lockedBalance":{

}
},
"id":1
}

以下示例演示了如何在 Rust 中使用 sui_getBalance

use std::str::FromStr;
use sui_sdk::types::base_types::SuiAddress;
use sui_sdk::{SuiClient, SuiClientBuilder};


#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let sui = SuiClientBuilder::default().build(
"https://fullnode.devnet.sui.io:443",
).await.unwrap();
let address = SuiAddress::from_str("0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3")?;
let objects = sui.read_api().get_balance(address).await?;
println!("{:?}", objects);
Ok(())
}

使用事件跟踪地址的余额变化

你还可以通过订阅从地址发出的所有事件来跟踪其余额。使用过滤器仅包括与 SUI 币相关的事件,例如地址获得币或支付燃气费用。 以下示例演示了如何使用 bash 和 cURL 为地址过滤事件:

rpc="https://fullnode.devnet.sui.io:443"
address="0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3"
data="{\"jsonrpc\": \"2.0\", \"id\":1, \"method\": \"sui_getEvents\", \"params\": [{\"Recipient\": {\"AddressOwner\": \"0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3\"}}, null, null, true ]}"
curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc

响应可能包含大量事件。通过请求中的 nextCursor 键向响应添加分页。你可以从事务的 id 字段确定相应的 txDigesteventSeq

你可以将 params 中的第一个 null 替换为 txDigest 值。第二个 null 是一个整数,定义要返回的结果数量(最多 1000 个),而 true 表示升序。你可以使用 nextCursor 以便响应从所需点开始。

任何事务的 id 字段如下所示:

"id": {
"txDigest": "GZQN9pE3Zr9ZfLzBK1BfVCXtbjx5xKMxPSEKaHDvL3E2",
"eventSeq": 6019
}

使用这些数据,创建 nextCursor 如下所示:

nextCursor : {"txDigest": "GZQN9pE3Zr9ZfLzBK1BfVCXtbjx5xKMxPSEKaHDvL3E2","eventSeq": 6019}

区块与检查点

Sui 是基于 DAG 的区块链,并使用检查点进行节点同步和全局交易排序。检查点与区块的不同之处在于:

  • Sui 创建检查点并添加已完成的事务。请注意,即使在事务包含在检查点之前,它们也会被完成。
  • 检查点不会分叉、回滚或重新组织。
  • Sui 每约 3 秒创建一个检查点。

检查点 API 操作

Sui 检查点 API 操作包括:

SUI 余额转移

要在地址之间转移特定数量的 SUI,你需要一个具有该特定值的 SUI 代币对象。在 Sui 中,所有东西都是对象,包括 SUI 代币。每个 SUI 代币对象中的 SUI 量是不同的。例如,一个地址可能拥有 3 个具有不同值的 SUI 代币:一个值为 0.1 SUI,第二个值为 1.0 SUI,第三个值为 0.005 SUI。地址的总余额等于个别 SUI 代币对象值的总和,在这种情况下为 1.105 SUI。

你可以合并和拆分 SUI 代币对象以创建具有特定值的代币对象。要创建价值为 0.6 SUI 的 SUI 代币,将价值为 1 SUI 的代币拆分为两个价值分别为 0.6 SUI 和 0.4 SUI 的代币对象。

要转移特定金额的 SUI,你需要一个价值该特定金额的 SUI 代币。要获取具有该特定值的 SUI 代币,你可能需要拆分或合并现有的 SUI 代币。Sui 支持多种方法来完成此操作,包括一些无需手动拆分或合并硬币的方法。

用于转移的 Sui API 操作

Sui 支持以下与地址之间转移 SUI 相关的 API 操作:

  • sui_transferObject 由于 SUI 代币是对象,因此你可以像处理其他对象一样转移 SUI 代币。此方法需要一个燃气代币,仅在特定情况下有用。

  • sui_payAllSui 此方法接受 SUI 代币 ID 数组。它将所有现有代币合并成一个,扣除燃气费用,然后将合并的代币发送到接收地址。

    如果要转移地址的所有 SUI,则此方法特别有用。要将地址的所有硬币合并在一起,请将接收方设置为相同的地址。这是一种本地 Sui 方法,因此在 Sui 中不被视为交易。它们的燃气费用与 Sui 上的典型交易相匹配。你可以使用此操作通过将接收方设置为自己的地址拆分自己地址中的硬币。请注意,输入硬币的总价值必须大于要发送的总金额。

  • sui_paySui 此方法类似于 sui_paySui,但接受任何类型的硬币或代币,而不仅仅是 SUI。你必须包括一个燃气代币,并且所有硬币或代币必须是相同类型的。

  • sui_transferSui 此方法仅接受一个 SUI 代币对象和要发送到接收方的金额。它使用相同的代币支付燃气费用,因此要转移的金额必须严格小于所使用的 SUI 代币的值。

签名交易

有关签名有效性要求的详细信息,请参阅 Sui 签名

SUI 质押

Sui 区块链使用委托权益证明(DPoS)机制。这使得 SUI 代币持有者可以将其 SUI 代币委托给其选择的任何验证器。当有人委托其 SUI 代币时,这意味着这些代币将被锁定整个时期。用户可以随时撤回他们的委托,但新的质押请求仅在下一时期开始时生效。

将 SUI 代币委托给验证器的 SUI 持有者因协助保护 Sui 网络而获得奖励。Sui 根据网络上的质押奖励确定质押的奖励,并在每个时期结束时分发它们。

Sui 网络中的总投票权总是为 10,000。每个个体验证器的投票权类似于基点。例如,投票权为 101 = 1.01%。Sui 的法定门槛(确认交易所需的票数)为 6,667(大于 2/3)。单个验证器的投票权上限为 1,000(10%),无论验证器拥有多少质押。

质押功能

Sui 支持以下与质押相关的 API 操作。你可以在 sui_system 模块中找到源代码。

  • request_add_stake 向验证器的质押池添加用户质押。
public fun request_add_stake(
self: &mut SuiSystemState,
stake: Coin<SUI>,
validator_address: address,
ctx: &mut TxContext,
) {
validator_set::request_add_stake(
&mut self.validators,
validator_address,
coin::into_balance(stake),
option::none(),
ctx,
);
}
  • request_add_stake_mul_coin 使用多个代币向验证器的质押池添加用户质押。
public fun request_add_stake_mul_coin(
self: &mut SuiSystemState,
delegate_stakes: vector<Coin<SUI>>,
stake_amount: option::Option<u64>,
validator_address: address,
ctx: &mut TxContext,
) {
let balance = extract_coin_balance(delegate_stakes, stake_amount, ctx);
validator_set::request_add_stake(&mut self.validators, validator_address, balance, option::none(), ctx);
}
  • request_add_stake_with_locked_coin 使用锁定的 SUI 代币将用户质押添加到验证者的质押池中。
public fun request_add_stake_with_locked_coin(
self: &mut SuiSystemState,
stake: LockedCoin<SUI>,
validator_address: address,
ctx: &mut TxContext,
) {
let (balance, lock) = locked_coin::into_balance(stake);
validator_set::request_add_stake(&mut self.validators, validator_address, balance, option::some(lock), ctx);
}
  • request_withdraw_stake 从验证者的质押池中提取部分用户质押。
public fun request_withdraw_stake(
self: &mut SuiSystemState,
delegation: &mut Delegation,
staked_sui: &mut StakedSui,
principal_withdraw_amount: u64,
ctx: &mut TxContext,
) {
validator_set::request_withdraw_stake(
&mut self.validators,
delegation,
staked_sui,
principal_withdraw_amount,
ctx,
);
}