# TS

### SDK

请在运行示例代码前安裝`blockrazor-sui-sdk`和`@mysten/sui`，安裝命令：

```bash
## blockrazor-sui-sdk
npm i blockrazor-sui-sdk

## @mysten/sui
npm install @mysten/sui
```

### gRPC

[示例地址](https://github.com/BlockRazorinc/sui_ts_example/blob/main/example/demo_grpc.ts)

```typescript
import { Transaction } from "@mysten/sui/transactions";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";
import { SuiClient, SuiHTTPTransport, getFullnodeUrl } from "@mysten/sui/client";
import * as grpc from "@grpc/grpc-js";
import * as protoLoader from "@grpc/proto-loader";
import path from "path";
import { CaculateFee, AddTip } from "blockrazor-sui-sdk";
import { CompressionFilter } from "@grpc/grpc-js/build/src/compression-filter.js";


// Replace with your own private key
const SUI_PRIVATE_KEY = "suiprivkey1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

// Receiver address
const RECIPIENT = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

// gRPC endpoint 
const GRPC_ADDR = "your-grpc-host:PORT";

// JSON-RPC endpoint 
const RPC_URL = getFullnodeUrl("mainnet");

// Auth token
const AUTH_TOKEN = "YOUR_AUTH_TOKEN";

// Amount to send (in MIST)
const SEND_AMOUNT_MIST = 1_000_000n;

// Fixed gas price for demo
const GAS_PRICE = 5_000;

/**
 * Local proto root (change this path to match your repo structure)
 */
const PROTO_ROOT = path.resolve("/path/to/your/protos");

/**
 * Proto file for:
 * package sui.rpc.v2;
 * service TransactionExecutionService { rpc ExecuteTransaction(...) ... }
 */
const PROTO_FILE = path.join(
    PROTO_ROOT,
    "sui/rpc/v2/transaction_execution_service.proto"
);

function forceIdentityGrpcEncoding() {
    const proto = CompressionFilter.prototype as CompressionFilter & {
        __identityEncodingPatched?: boolean;
    };
    if (proto.__identityEncodingPatched) {
        return;
    }

    proto.__identityEncodingPatched = true;
    proto.sendMetadata = async function (metadataPromise) {
        const headers = await metadataPromise;
        // Some gateways mis-handle grpc-js advertised encodings and treat
        // the request as gzip-compressed even when the payload is identity.
        headers.set("grpc-accept-encoding", "identity");
        headers.set("accept-encoding", "identity");
        headers.remove("grpc-encoding");
        return headers;
    };
}


function makeGrpcClient() {
    forceIdentityGrpcEncoding();
    const pkgDef = protoLoader.loadSync(PROTO_FILE, {
        includeDirs: [PROTO_ROOT],
        keepCase: false,
        longs: String,
        enums: String,
        defaults: false,
        oneofs: true,
    });

    const loaded: any = grpc.loadPackageDefinition(pkgDef);
    const Svc = loaded.sui.rpc.v2.TransactionExecutionService;
    return new Svc(GRPC_ADDR, grpc.credentials.createInsecure(), {
        "grpc.default_compression_algorithm": grpc.compressionAlgorithms.identity,
    });
}

/**
 * ExecuteTransaction RPC call with auth metadata.
 */
function grpcExecuteTransaction(client: any, req: any, authToken: string): Promise<any> {
    return new Promise((resolve, reject) => {
        const md = new grpc.Metadata();
        md.set("auth_token", authToken);
        client.ExecuteTransaction(req, md, (err: any, resp: any) => {
            if (err) return reject(err);
            resolve(resp);
        });
    });
}


async function main() {
    const { secretKey } = decodeSuiPrivateKey(SUI_PRIVATE_KEY);
    const keypair = Ed25519Keypair.fromSecretKey(secretKey);
    const sender = keypair.getPublicKey().toSuiAddress();
    console.log("sender:", sender);

    // Build a simple transfer transaction ---
    const tx = new Transaction();
    tx.setSender(sender);
    tx.setGasPrice(GAS_PRICE);

    // Split gas coin into payment coin, then transfer to recipient
    const [payCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(SEND_AMOUNT_MIST)]);
    tx.transferObjects([payCoin], tx.pure.address(RECIPIENT));

    // JSON-RPC client used for tx.build()
    const httpTransport = new SuiHTTPTransport({
        url: RPC_URL,
        rpc: {
            headers: {
                auth_token: AUTH_TOKEN,
            },
        },
    });
    const httpClient = new SuiClient({ transport: httpTransport });

    // === Estimate gas & tip 
    const estimatedFee = await CaculateFee({ transaction: tx });
    console.log("Estimated Fee:", estimatedFee);

    tx.setGasBudget(estimatedFee.gasBudget);
    AddTip(tx, Math.max(estimatedFee.tipAmount, 1_000_000));

    // Build transaction
    const transactionBytes = await tx.build({ client: httpClient });

    // Sign transaction
    const signed = await keypair.signTransaction(transactionBytes);

    const sigBytes = Buffer.from(signed.signature, "base64");

    // Create gRPC client + send ExecuteTransaction request
    const grpcClient = makeGrpcClient();
    const req = {
        transaction: { bcs: { value: Buffer.from(transactionBytes) } },
        signatures: [{ bcs: { value: sigBytes } }],
    };

    // Send transaction
    const resp = await grpcExecuteTransaction(grpcClient, req, AUTH_TOKEN);
    console.log("grpc resp:", resp);
}

main().catch((err) => {
    console.error("Execution failed:", err);
    process.exit(1);
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.blockrazor.io/tc/transaction-submission/fast/sui/sui_executetransactionblock/ts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
