# Delegated Staking

## Delegated Staking Integration Guide

{% hint style="warning" %}
This feature is currently available on IntegrationNet only.&#x20;
{% endhint %}

This guide walks you through integrating with Constellation Network’s Delegated Staking system, including how to create, update, and withdraw delegated stakes for users that want to automate this process through the network APIs.&#x20;

Delegated staking allows users to lock their tokens on the network and delegate them to a node operator, receiving a share of the validator’s rewards in return. The process relies on TokenLocks and is managed via the Global L0 (gL0) and DAG L1 (dagL1) APIs.

Manual staking using Stargazer Wallet is supported through the [DAG Explorer](https://integrationnet.dagexplorer.io) website.

{% hint style="success" %}

### Node Operators

For node operators looking for information on how to participate in Delegated Staking and how to attract delegators to their nodes, see [Node Operator Delegated Staking](https://app.gitbook.com/s/ZrtHSqcmP0ydsdSnYXRM/validator-node-guides/delegated-staking/for-node-operators).
{% endhint %}

***

## API Reference Summary

Before getting started, familiarize yourself with the following endpoints. Note that you'll be interacting with API endpoints on both the [DAG L1](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#dag-l1-api) and [Global L0](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#global-l0-api) APIs.&#x20;

| Endpoint                               | API                                                                                                  | Method | Description                                                  |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------ |
| `/token-locks`                         | [DAG L1](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#dag-l1-api) | `POST` | Submit a TokenLock.                                          |
| `/token-locks/:address/last-reference` | [DAG L1](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#dag-l1-api) | `GET`  | Get the latest transaction reference for use in a TokenLock. |
| `/delegated-stakes/:address/info`      | [gL0](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#global-l0-api) | `GET`  | Fetch current delegated stake positions for an address.      |
| `/delegated-stakes`                    | [gL0](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#global-l0-api) | `POST` | Create or update a delegated stake position.                 |
| `/delegated-stakes`                    | [gL0](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#global-l0-api) | `PUT`  | Withdraw a delegated stake position.                         |
| `/node-params`                         | [gL0](https://docs.constellationnetwork.io/network-apis/api-reference/hypergraph-apis#global-l0-api) | `GET`  | Fetch node metadata including node IDs and reward settings.  |

***

## Transaction Signing

All `POST` and `PUT` requests below follow the brotli compressed signing scheme described in [Transaction Signing](https://docs.constellationnetwork.io/network-apis/transaction-signing#overview). If using a library like [dag4.js](https://github.com/StardustCollective/dag4.js) to generate and send requests to the network, serialization and signing will be handled for you automatically. If sending requests directly to the REST APIs without using a library, you will need to generate the signatures manually.&#x20;

## Creating a Delegated Stake

To create a delegated stake, follow these steps:

#### 1. Discover Available Nodes

Use the following API call to list the nodes currently accepting delegated stakes:

{% tabs %}
{% tab title="Bash" %}
{% code overflow="wrap" %}

```bash
curl -X GET "{GL0_API}/node-params" -H "Content-Type: application/json"
```

{% endcode %}
{% endtab %}
{% endtabs %}

Each node record includes:

* `nodeId`: used to delegate
* `name`: name provided by the operator&#x20;
* `description`: description provided by the operator
* `rewardFraction`: the validator's share of rewards

You’ll use the `nodeId` from this list when creating your stake.

***

#### 2. Fetch TokenLock Parent Reference

Before creating a TokenLock, you need the last reference for your wallet address:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X GET "{DAGL1_API}/token-locks/{address}/last-reference" -H "Content-Type: application/json"
```

{% endtab %}

{% tab title="Dag4.js" %}
This step can be skipped w/dag4.js. The parent reference will be fetched automatically when creating the TokenLock.&#x20;
{% endtab %}
{% endtabs %}

This value will be used as the `parentReference` in your new TokenLock transaction.

***

#### 3. Create the TokenLock

Submit a TokenLock to lock your tokens:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X POST "{DAGL1_API}/token-locks" -H "Content-Type: application/json" -d '{
  "value": {
    "source": "DAG4xPWQj3BpAg2YKg3kbdW2AJcMfZz2SUKqYb1t",
    "amount": 100000000,
    "fee": 0,
    "parent": {YOUR_PARENT_REFERENCE},
    "currencyId": null,
    "unlockEpoch": null
  },
  "proofs":[{
    "id": "c7f9a08bdea7ff5f51c8af16e223a1d751bac9c541125d9aef5658e9b7597aee8cba374119ebe83fb9edd8c0b4654af273f2d052e2d7dd5c6160b6d6c284a17c",
    "signature": "3045022017607e6f32295b0ba73b372e31780bd373322b6342c3d234b77bea46adc78dde022100e6ffe2bca011f4850b7c76d549f6768b88d0f4c09745c6567bbbe45983a28bf1"
  }]
}'
```

{% endtab %}

{% tab title="Dag4.js" %}

```typescript
import { dag4 } from '@stardust-collective/dag4'

dag4.account.loginSeedPhrase(YOUR_SEED_PHRASE)

dag4.account.connect({
  networkVersion: '2.0',
  l0Url: {GL0_API},
  l1Url: {DAGL1_API}
})

await dag4.account.postTokenLock({
  source: dag4.account.address,
  amount: 500000000000,
  fee: 0,
  tokenL1Url: {DAGL1_API},
  unlockEpoch: null,
  currencyId: null,
})
```

{% endtab %}
{% endtabs %}

* `source`**:** set to the address of the wallet sending the request
* `amount`: number of tokens to lock (in smallest unit, i.e., datum)
* `fee`: set to zero
* `currencyId`: set to `null`
* `unlockEpoch`: set to `null` — this ensures only the network can unlock the tokens upon withdrawal
* `parent`: from previous step

***

#### 4. Fetch DelegatedStake Parent Reference

Now fetch your DelegatedStake's last reference:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X GET "{GL0_API}/delegated-stakes/{address}/info" -H "Content-Type: application/json"
```

{% endtab %}

{% tab title="Dag4.js" %}
This step can be skipped w/dag4.js. The parent reference will be fetched automatically when creating the DelegatedStake.&#x20;
{% endtab %}
{% endtabs %}

Use the returned value as `parent` when submitting the new stake.

***

#### 5. Submit Delegated Stake Request

Now that you have your `tokenLockRef` and parent reference, submit the stake:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X POST "{GL0_API}/delegated-stakes" -H "Content-Type: application/json" -d '{
  "value": {
    "source": "{SENDER_ADDRESS}",
    "nodeId": "{NODE_ID}",
    "amount": 100000000,
    "fee": 0,
    "tokenLockRef": {TOKEN_LOCK_REF},
    "parent": {PARENT_REFERENCE}
  },
  "proofs":[{
    "id": "c7f9a08bdea7ff5f51c8af16e223a1d751bac9c541125d9aef5658e9b7597aee8cba374119ebe83fb9edd8c0b4654af273f2d052e2d7dd5c6160b6d6c284a17c",
    "signature": "3045022017607e6f32295b0ba73b372e31780bd373322b6342c3d234b77bea46adc78dde022100e6ffe2bca011f4850b7c76d549f6768b88d0f4c09745c6567bbbe45983a28bf1"
  }]
}'
```

{% endtab %}

{% tab title="Dag4.js" %}

```typescript
import { dag4 } from '@stardust-collective/dag4'

dag4.account.loginSeedPhrase(YOUR_SEED_PHRASE)

dag4.account.connect({
  networkVersion: '2.0',
  l0Url: {GL0_API},
  l1Url: {DAGL1_API}
})

await dag4.account.postDelegatedStake({
  source: dag4.account.address,
  nodeId: "{NODE_ID}",
  amount: 500000000000,
  fee: 0,
  tokenLockRef: "{TOKEN_LOCK_REF}"
})
```

{% endtab %}
{% endtabs %}

Request body includes:

* `nodeId`: from `/node-params`
* `amount`: must exactly match the amount of the TokenLock referenced
* `fee`: should be zero
* `tokenLockRef`: from TokenLock response
* `parent`: from `/delegated-stakes/:address/info`

If successful, a `hash` of the DelegatedStake record will be returned.&#x20;

***

#### 6. Verify Stake Activation

Use:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X GET "{GL0_API}/delegated-stakes/{address}/info" -H "Content-Type: application/json"
```

{% endtab %}
{% endtabs %}

Check that your stake is listed in the `activeDelegatedStakes` array, and that `rewardsAmount` is increasing.

***

## Updating a Delegated Stake

Delegated stakes can be redirected to a new node **without withdrawal** or penalty.

#### 1. Pick a New Node

Re-run:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X GET "{GL0_API}/node-params" -H "Content-Type: application/json"
```

{% endtab %}
{% endtabs %}

Choose a new node ID to delegate to.

***

#### 2. Re-submit the DelegatedStake

Use the **same** `tokenLockRef` **and stake amount**, but change the `nodeId`.

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X POST "{GL0_API}/delegated-stakes" -H "Content-Type: application/json" -d '{
  "value": {
    "source": "{SENDER_ADDRESS}",
    "nodeId": "{NEW_NODE_ID}",
    "amount": 100000000,
    "fee": 0,
    "tokenLockRef": {TOKEN_LOCK_REF},
    "parent": {PARENT_REFERENCE}
  },
  "proofs":[{
    "id": "c7f9a08bdea7ff5f51c8af16e223a1d751bac9c541125d9aef5658e9b7597aee8cba374119ebe83fb9edd8c0b4654af273f2d052e2d7dd5c6160b6d6c284a17c",
    "signature": "3045022017607e6f32295b0ba73b372e31780bd373322b6342c3d234b77bea46adc78dde022100e6ffe2bca011f4850b7c76d549f6768b88d0f4c09745c6567bbbe45983a28bf1"
  }]
}'
```

{% endtab %}

{% tab title="Dag4.js" %}

```typescript
import { dag4 } from '@stardust-collective/dag4'

dag4.account.loginSeedPhrase(YOUR_SEED_PHRASE)

dag4.account.connect({
  networkVersion: '2.0',
  l0Url: {GL0_API},
  l1Url: {DAGL1_API}
})

await dag4.account.postDelegatedStake({
  source: dag4.account.address,
  nodeId: "{NEW_NODE_ID}",
  amount: 500000000000,
  fee: 0,
  tokenLockRef: "{TOKEN_LOCK_REF}"
})
```

{% endtab %}
{% endtabs %}

This will update the position to the new node without incurring a withdrawal penalty. All fields other than `nodeId` must remain the same as the original request.

***

#### 3. Confirm the Update

Use:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X GET "{GL0_API}/delegated-stakes/{address}/info" -H "Content-Type: application/json"
```

{% endtab %}
{% endtabs %}

Ensure the `nodeId` has updated and `rewardAmount` continues to increase.&#x20;

***

## Withdrawing a Delegated Stake

To withdraw a delegated stake (unlock your tokens and receive rewards), follow this process:

#### 1. Submit Withdrawal Request

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X PUT "{GL0_API}/delegated-stakes" -H "Content-Type: application/json" -d '{
  "source": "{SENDER_ADDRESS}",
  "stakeRef": "{DELEGATED_STAKE_REFERENCE}"
}'
```

{% endtab %}

{% tab title="Dag4.js" %}

```typescript
dag4.account.loginSeedPhrase(YOUR_SEED_PHRASE)

dag4.account.connect({
  networkVersion: '2.0',
  l0Url: {GL0_API},
  l1Url: {DAGL1_API}
})

await dag4.account.putWithdrawDelegatedStake({
    source: dag4.account.address,
    stakeRef: "{DELEGATED_STAKE_REFERENCE}"
})
```

{% endtab %}
{% endtabs %}

You’ll need:

* Reference to the original DelegatedStake position

This will **start the 21-day unbonding period**.

***

#### 2. Verify Pending Status

After submitting, verify the stake has moved to `pendingWithdrawals`:

{% tabs %}
{% tab title="Bash" %}

```bash
curl -X GET "{GL0_API}/delegated-stakes/{address}/info" -H "Content-Type: application/json"
```

{% endtab %}
{% endtabs %}

During this time:

* The position no longer accrues rewards
* Tokens remain locked

***

#### 3. Wait and Confirm Completion

After \~21 days (estimated in network `epochProgress`), check your wallet:

* TokenLock should be removed
* Rewards should be distributed in a reward transaction
