Skip to content

Commit

Permalink
Merge pull request #94 from ayo-klaytn/add/kaia-safe-api-kit
Browse files Browse the repository at this point in the history
kaia safe api kit added
  • Loading branch information
ayo-klaytn authored Sep 3, 2024
2 parents 0435e4e + 1435d84 commit 06afa3f
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 1 deletion.
271 changes: 271 additions & 0 deletions docs/build/tools/wallets/kaia-safe/kaia-safe-api-kit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
---
id: kaia-safe-api-kit
title: Kaia Safe API-Kit
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Kaia Safe API Kit

API-Kit is your go-to kit for securely interacting with the [Safe Transaction API](https://github.com/safe-global/safe-transaction-service). The core of this kit is to allow valid signers to propose and share transactions with the other signers of a Safe, send the signatures to the service to collect them, and get information about a Safe (like reading the transaction history, pending transactions, enabled Modules and Guards, etc.), among other features.

## Quickstart <a id="Quickstart"></a>

By the end of this guide, you will be able to propose transactions to the service and obtain the owners' signatures for execution.

## Prerequisites <a id="Prerequisites"></a>

1. [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
2. A Safe with several signers

## Set up environment <a id="Setup-environment"></a>

### Step 1: Create a project directory.

Copy and paste this command in your terminal to create the project folder.

```js
mkdir kaiasafe-api-kit
cd kaiasafe-api-kit
```

### Step 2: Initialize an npm project.

Copy and paste this command in your terminal to create a `package.json` file.

```js
npm init -y
```

### Step 3: Install dependencies.

Using API-Kit is as simple as running the installation command below:


<Tabs>
<TabItem value="npm" label="npm">
```
npm install @safe-global/api-kit @safe-global/protocol-3 @safe-global/safe-core-sdk-types
```
</TabItem>

<TabItem value="yarn" label="yarn">
```
yarn add @safe-global/api-kit @safe-global/protocol-kit @safe-global/safe-core-sdk-types
```
</TabItem>
</Tabs>

### Step 4: Import dependencies.

Create a file named `app.js`. This is where all our code snippets for this interaction would live.

Copy and paste these necessary imports at the top of the `app.js` file.

```js
import SafeApiKit from '@safe-global/api-kit'
import Safe from '@safe-global/protocol-kit'
import {
OperationType
} from '@safe-global/safe-core-sdk-types'
```

### Step 5: Configure Setup

To efficiently illustrate how API-Kit works, we will use a Safe account setup with two or more signers, and threshold two, so we have multiple signatures that need to be collected when executing a transaction.

Copy and paste the following under the import statements in your `app.js` file:

```js
// https://chainlist.org/?search=kaia&testnets=true
const RPC_URL = 'https://public-en-kairos.node.kaia.io'
const SAFE_ADDRESS = "<REPLACE WITH SAFE PUBLIC ADDRESS HERE>"; // 2 Owner Safe Address Ex: 0x123.... SAFE SHOULD
const OWNER_1_ADDRESS = "<REPLACE WITH OWNER 1 PUBLIC KEY HERE>"; // ONLY OWNER 1 and SAFE ADDRESS Need to have some test KAIA balance
const OWNER_1_PRIVATE_KEY = "<REPLACE WITH OWNER 1 PRIVATE KEY HERE>";
const OWNER_2_PRIVATE_KEY = "<REPLACE WITH OWNER 2 PRIVATE KEY HERE>"; // OWNER 2 need not have any test KAIA
const TO_ADDRESS = OWNER_1_ADDRESS; // Receiver address of sample transaction who receives 1 wei
```

## Use API Kit <a id="use-api-kit"></a>

### Step 1: Initialize API Kit

To initialize API Kit, we need to create an instance of the API Kit.

> In chains where the [Safe Transaction Service](https://docs.safe.global/core-api/transaction-service-overview) is supported, it's enough to specify the chainId property.
```js
const apiKit = new SafeApiKit.default({
chainId: 1001n,
txServiceUrl: 'https://docs-safe.kaia.io/txs-baobab/api'
})

```

As you can see above, we included custom service using the optional **txServiceUrl** property.

### Step 2: Initialize Protocol Kit

To handle transactions and signatures, we need to create an instance of the Protocol Kit (a kit that enables developers to interact with [Safe Smart Accounts](https://github.com/safe-global/safe-smart-account) using a TypeScript interface) with the provider, signer and safeAddress.

```js
const protocolKitOwner1 = await Safe.default.init({
provider: RPC_URL,
signer: OWNER_1_PRIVATE_KEY,
safeAddress: SAFE_ADDRESS
})
```

### Step 3: Propose a transaction to the service

One of the core features of API Kit is to enable valid signers to share transactions with other signers. But before this is done, any of the Safe signers needs to initiate the process by creating a proposal of a transaction. This transaction is then sent to the service to make it accessible by the other owners so they can give their approval and sign the transaction as well.

```js
const safeTransactionData = {
to: TO_ADDRESS,
value: '1', // 1 wei
data: '0x',
operation: OperationType.Call
}
const safeTransaction = await protocolKitOwner1.createTransaction({
transactions: [safeTransactionData]
})
const safeTxHash = await protocolKitOwner1.getTransactionHash(safeTransaction)
const signature = await protocolKitOwner1.signHash(safeTxHash)
// 2. Propose transaction to the service
try {
await apiKit.proposeTransaction({
safeAddress: SAFE_ADDRESS,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress: OWNER_1_ADDRESS,
senderSignature: signature.data
})
} catch(err) {
console.log(err)
}
```

### Step 4: Retrieve pending transaction

API Kit provides us different methods to retrieve pending transactions depending on the situation. For this guide, we will retrieve a transaction given the Safe transaction hash and other available methods commented out below:

```js
const transaction = await apiKit.getTransaction(safeTxHash)
// const transactions = await service.getPendingTransactions()
// const transactions = await service.getIncomingTransactions()
// const transactions = await service.getMultisigTransactions()
// const transactions = await service.getModuleTransactions()
// const transactions = await service.getAllTransactions()
```

## Step 5: Confirm the transaction

The next thing to do is to sign the transaction with the Protocol Kit and submit the signature to the Safe Transaction Service using the [confirmTransaction](https://docs.safe.global/sdk/api-kit/reference#confirmtransaction) method.

```js
const protocolKitOwner2 = await Safe.default.init({
provider: RPC_URL,
signer: OWNER_2_PRIVATE_KEY,
safeAddress: SAFE_ADDRESS
})
const signature2 = await protocolKitOwner2.signHash(safeTxHash)
// Confirm the Safe transaction
const signatureResponse = await apiKit.confirmTransaction(
safeTxHash,
signature2.data
)
```

### Step 6: Execute the transaction

The Safe transaction is now ready to be executed. This can be done using the [Safe Wallet Web](https://app.safe.global/) interface, the [Protocol Kit](https://docs.safe.global/sdk/protocol-kit#execute-the-transaction), the Safe CLI or any other tool that's available.

For this last step, we executed the safe transaction using Protocol Kit.

```js
const safeTxn = await apiKit.getTransaction(safeTxHash);
const executeTxReponse = await protocolKitOwner1.executeTransaction(safeTxn)
const receipt = await executeTxReponse.transactionResponse?.wait();
console.log('Transaction executed:');
console.log(`https://kairos.kaiascan.io/tx/${hash}`)
```
At the end, the full code in `app.js` should look like this:
```js
import SafeApiKit from '@safe-global/api-kit'
import Safe from '@safe-global/protocol-kit'
import {
OperationType
} from '@safe-global/safe-core-sdk-types'
// https://chainlist.org/?search=kaia&testnets=true
const RPC_URL = 'https://public-en-kairos.node.kaia.io'
const SAFE_ADDRESS = "<REPLACE WITH SAFE PUBLIC ADDRESS HERE>"; // 2 Owner Safe Address Ex: 0x123.... SAFE SHOULD
const OWNER_1_ADDRESS = "<REPLACE WITH OWNER 1 PUBLIC KEY HERE>"; // ONLY OWNER 1 and SAFE ADDRESS Need to have some test KAIA balance
const OWNER_1_PRIVATE_KEY = "<REPLACE WITH OWNER 1 PRIVATE KEY HERE>";
const OWNER_2_PRIVATE_KEY = "<REPLACE WITH OWNER 2 PRIVATE KEY HERE>"; // OWNER 2 need not have any test KAIA
const TO_ADDRESS = OWNER_1_ADDRESS; // Receiver address of sample transaction who receives 1 wei
const apiKit = new SafeApiKit.default({
chainId: 1001n,
txServiceUrl: 'https://docs-safe.kaia.io/txs-baobab/api'
})
const protocolKitOwner1 = await Safe.default.init({
provider: RPC_URL,
signer: OWNER_1_PRIVATE_KEY,
safeAddress: SAFE_ADDRESS
})
// 1. Create transaction
const safeTransactionData = {
to: TO_ADDRESS,
value: '1', // 1 wei
data: '0x',
operation: OperationType.Call
}
const safeTransaction = await protocolKitOwner1.createTransaction({
transactions: [safeTransactionData]
})
const safeTxHash = await protocolKitOwner1.getTransactionHash(safeTransaction)
const signature = await protocolKitOwner1.signHash(safeTxHash)
// 2. Propose transaction to the service
try {
await apiKit.proposeTransaction({
safeAddress: SAFE_ADDRESS,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress: OWNER_1_ADDRESS,
senderSignature: signature.data
})
} catch(err) {
console.log(err)
}
console.log("Transaction hash is "+safeTxHash)
const transaction = await apiKit.getTransaction(safeTxHash)
// const transactions = await service.getPendingTransactions()
// const transactions = await service.getIncomingTransactions()
// const transactions = await service.getMultisigTransactions()
// const transactions = await service.getModuleTransactions()
// const transactions = await service.getAllTransactions()
// 3. Confirmation from Owner 2
const protocolKitOwner2 = await Safe.default.init({
provider: RPC_URL,
signer: OWNER_2_PRIVATE_KEY,
safeAddress: SAFE_ADDRESS
})
const signature2 = await protocolKitOwner2.signHash(safeTxHash)
// Confirm the Safe transaction
const signatureResponse = await apiKit.confirmTransaction(
safeTxHash,
signature2.data
)
console.log(signatureResponse)
// 4. Execute transaction
const safeTxn = await apiKit.getTransaction(safeTxHash);
const executeTxReponse = await protocolKitOwner1.executeTransaction(safeTxn)
const receipt = await executeTxReponse.transactionResponse?.wait();
console.log('Transaction executed:');
console.log(`https://kairos.kaiascan.io/tx/${hash}`)
```
Visit the [API Kit Reference](https://docs.safe.global/sdk/api-kit/reference) for more information, and navigate to [Github](https://github.com/kaiachain/kaia-dapp-mono/tree/main/examples/snippets) to access the full source code for this guide.
35 changes: 34 additions & 1 deletion docs/build/tools/wallets/kaia-safe/tx-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,40 @@ This is a custom app in Kaia Safe that is responsible for batching transactions.

With transaction builder, you can compose transactions from token transfers to complex contract interactions and batch them into a single transaction.

**Illustration**

## KLAY Token Transfer <a id="token-transfer"></a>
You can perform token transfer using transaction builder by following the steps below:

**Step 1:** Navigate to Safe Apps and open Transaction Builder Safe App

![](/img/build/tools/kaia-safe/ks-tx-builder.png)

**Step 2:** Enter the recipient wallet address. For this guide, kindly skip the ABI field as we are trying to execute KLAY transfer transaction.

![](/img/build/tools/kaia-safe/tx-builder-token-recipient-addr.png)


**Step 3:** Enter the KLAY value you want to send.

> Note: In this guide, we are sending 1 KLAY, so we entered 1 in the **KLAY value** input field. You can input any amount here, depending on your Safe's KLAY balance.
![](/img/build/tools/kaia-safe/tx-builder-token-trf-value.png)

**Step 4:** Click Add transaction.

**Step 5:** Repeat steps 2, 3, and 4 for every recipient address.

**Step 6:** Once you added all operations to the batch click Create Batch.

![](/img/build/tools/kaia-safe/token-trf-tx-builder.gif)


**Step 7:** Review and submit transaction

You'll be able to review the whole batch. Once ready, click Send Batch to submit and execute the transaction just like any other Safe transaction.


## Contract Interactions <a id="contract-interactions"></a>

Let's say you want to airdrop tokens to a long list of addresses, say 10 CCT tokens to 5 addresses. Instead of having to create 5 transactions, which the owners of your safe have to confirm and execute one after the other, the transaction builder puts all these transfers into a single transaction.

Expand Down
1 change: 1 addition & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ const sidebars = {
'build/tools/wallets/kaia-safe/contract-interaction',
'build/tools/wallets/kaia-safe/tx-builder',
'build/tools/wallets/kaia-safe/faqs',
'build/tools/wallets/kaia-safe/kaia-safe-api-kit'
],
},
'build/tools/wallets/kaia-wallet',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 06afa3f

Please sign in to comment.