Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -686,4 +686,6 @@ Once a transfer transaction reaches `FINALIZED`, a `MultiTokens.Transferred` eve
For a comprehensive view of all available arguments for queries and mutations, please refer to our [API Reference](/03-api-reference/03-api-reference.md). This resource will guide you on how to use the GraphiQL Playground to explore the full structure and functionality of our API.

To sign with a managed wallet instead of the Wallet Daemon, set `signerAccount` on `CreateTransaction` / `CreateBatchTransaction`.

To move a managed wallet's **entire** balance out in one call — every token and all its ENJ, e.g. when migrating a player to a self-custodial wallet — use [`SweepManagedWallet`](/02-guides/01-platform/02-managing-users/03-using-managed-wallets.md#sweeping-a-managed-wallet) instead of assembling the transfers yourself.
:::
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Here's how the typical flow works:
1. **[Managed Wallet Creation](#creating-a-managed-wallet):** When a new user starts using your application, you initiate the creation of a managed wallet for them, and assign the user's internal ID from your database to the newly created managed wallet. This ensures a consistent link between the user and their wallet.
2. **[Asset Management](#minting-tokens-to-a-managed-wallet):** As the user earns or deposits digital assets within your application, these assets are automatically stored in their managed wallet.
3. **[In-App Transactions](#signing-transactions):** Any actions the user performs within your application that involve their wallet (e.g., spending tokens, participating in in-game economies) are executed directly on their managed wallet.
4. **[User Withdrawal (Optional)](#transferring-tokens-from-managed-wallets):** If a user decides they want to take full control of their assets, you can facilitate the transfer of all funds from their managed wallet to their own self-custodial wallet.
4. **[Graduating to Self-Custody (Optional)](#sweeping-a-managed-wallet):** If a user decides they want to take full control of their assets, a single [sweep](#sweeping-a-managed-wallet) moves every token and all their ENJ from their managed wallet to their own self-custodial wallet.

This process ensures that users can interact with blockchain assets seamlessly within your application without needing to understand the underlying complexities of blockchain technology or operating his own crypto wallet.

Expand Down Expand Up @@ -905,6 +905,109 @@ Make sure `signerExternalId` (or `signerAccount`) is set to the managed wallet t

Whether you're minting into a managed wallet or transferring out of one, the on-chain transaction emits the usual events on `FINALIZED` (e.g. `MultiTokens.Minted`, `MultiTokens.Transferred`) — with the managed wallet's address as the signer. See [Working with Events](/05-enjin-platform/03-working-with-events.md) for how to read them.

## Sweeping a Managed Wallet {#sweeping-a-managed-wallet}

Managed wallets make onboarding effortless: a player can start earning tokens and ENJ from their very first session, without ever setting up a wallet or learning anything about crypto. When that player later decides they're ready to take full ownership of what they've earned and move to a self-custodial wallet, you don't have to shuttle each asset out by hand.

The `SweepManagedWallet` mutation empties a managed wallet in a single call, sending **all** of its transferable tokens *and* its ENJ to a recipient address. That turns "graduating" to self-custody into a one-click step for the player.

Set the managed wallet as the signer (with `signerExternalId`, or `signerAccount` for its public key) and the player's self-custodial wallet as the `recipient`:

<Tabs>
<TabItem value="graphql" label="GraphQL">
```graphql
mutation SweepManagedWallet {
SweepManagedWallet(
network: CANARY
chain: MATRIX
signerExternalId: "docs-example-player" #The managed wallet to empty
recipient: "cxLf6yvvtscKrHRfKDphnzsT3eoRY45VbJvqXKub5pmj5mdbQ" #The player's self-custodial wallet
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We strongly want to recommend that people use variables since there's a tendency to copy-and-paste and then simply modify the example value (eg. recipient) with a value that gets injected server-side (not via GraphQL Variables) and then there's a serious security concern.

It's better to be consistent with the documentation and teach the best practices: the use of variables within GraphQL.

```
</TabItem>
<TabItem value="curl" label="cURL">
```
curl --location 'https://platform.beta.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer enjin_api_key' \
-d '{"query":"mutation SweepManagedWallet {\r\n SweepManagedWallet(\r\n network: CANARY\r\n chain: MATRIX\r\n signerExternalId: \"docs-example-player\"\r\n recipient: \"cxLf6yvvtscKrHRfKDphnzsT3eoRY45VbJvqXKub5pmj5mdbQ\"\r\n )\r\n}","variables":{}}'
```
</TabItem>
<TabItem value="js" label="Javascript">
```javascript
fetch('https://platform.beta.enjin.io/graphql', {
method: 'POST',
headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
body: JSON.stringify({
query: `
mutation SweepManagedWallet {
SweepManagedWallet(
network: CANARY
chain: MATRIX
signerExternalId: "docs-example-player" #The managed wallet to empty
recipient: "cxLf6yvvtscKrHRfKDphnzsT3eoRY45VbJvqXKub5pmj5mdbQ" #The player's self-custodial wallet
)
}
`
}),
})
.then(response => response.json())
.then(data => console.log(data));
```
</TabItem>
<TabItem value="nodejs" label="Node.js">
```javascript
const axios = require('axios');

axios.post('https://platform.beta.enjin.io/graphql', {
query: `
mutation SweepManagedWallet {
SweepManagedWallet(
network: CANARY
chain: MATRIX
signerExternalId: "docs-example-player" #The managed wallet to empty
recipient: "cxLf6yvvtscKrHRfKDphnzsT3eoRY45VbJvqXKub5pmj5mdbQ" #The player's self-custodial wallet
)
}
`
}, {
headers: {'Content-Type': 'application/json','Authorization': 'Bearer Your_Platform_Token_Here'}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
```
</TabItem>
<TabItem value="python" label="Python">
```python
import requests

query = '''
mutation SweepManagedWallet {
SweepManagedWallet(
network: CANARY
chain: MATRIX
signerExternalId: "docs-example-player"
recipient: "cxLf6yvvtscKrHRfKDphnzsT3eoRY45VbJvqXKub5pmj5mdbQ"
)
}
'''

response = requests.post('https://platform.beta.enjin.io/graphql',
json={'query': query},
headers={'Content-Type': 'application/json', 'Authorization': 'Bearer Your_Platform_Token_Here'}
)
print(response.json())
```
</TabItem>
</Tabs>

A successful call returns `true`.

:::note Runs in the background

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need another note that SweepManagedWallet either requires ENJ in the user's managed wallet, or, needs to be combined with a fuel tank that permits the managed wallet to perform the sweep.

This documentation may be best if we combine it with a notice about 'Creating a Secure Fuel Tank for Managed Wallets Only' which explains requireSignature and its use.

The sweep is processed asynchronously and is **rate-limited to once per hour, per wallet**. The returned `true` confirms the sweep was accepted — not that every asset has arrived yet. Watch for the usual on-chain events (`MultiTokens.Transferred`, `Balances.Transfer`) to know when each transfer finalizes. See [Working with Events](/05-enjin-platform/03-working-with-events.md).
:::

:::info Explore More Arguments
For a comprehensive view of all available arguments for queries and mutations, please refer to our [API Reference](/03-api-reference/03-api-reference.md). This resource will guide you on how to use the GraphiQL Playground to explore the full structure and functionality of our API.
:::
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ mutation MoveToCold {

### Move several items at once

If a player moves several different item types between inventories at once — a "withdraw everything to my wallet" button, say — bundle the actions into a single [`CreateBatchTransaction`](/03-api-reference/02-mutations/01-transaction-mutations.md) so they settle atomically with one fee instead of many.
If a player moves several different item types between inventories at once — bringing a whole loadout to hot at the start of a session, say — bundle the actions into a single [`CreateBatchTransaction`](/03-api-reference/02-mutations/01-transaction-mutations.md) so they settle atomically with one fee instead of many.

To empty a managed wallet completely — for instance when a player graduates their cold inventory to a self-custodial wallet — you don't need a batch at all: a single [`SweepManagedWallet`](/02-guides/01-platform/02-managing-users/03-using-managed-wallets.md#sweeping-a-managed-wallet) transfers every token and all their ENJ out in one call.

### Cover the fees

Expand Down
32 changes: 31 additions & 1 deletion docs/03-api-reference/02-mutations/04-wallets-mutations.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import TabItem from '@theme/TabItem';
`https://platform.beta.enjin.io/graphql`
:::

The Enjin Platform has one wallet-related mutation: `CreateManagedWallet`. Managed wallets are keypairs derived from the Wallet Daemon's seed plus an `externalId` you control — they let your application create signing accounts on demand without managing private keys.
The Enjin Platform has two wallet-related mutations: `CreateManagedWallet` and `SweepManagedWallet`. Managed wallets are keypairs derived from the Wallet Daemon's seed plus an `externalId` you control — they let your application create signing accounts on demand without managing private keys.

For end-user wallets connected via WalletConnect, there's no mutation here — the user's wallet already exists on chain. To submit transactions signed by an end-user wallet, see `CreateTransaction(..., signerAddress: <user-address>)` followed by `SignTransaction(uuid:, signedExtrinsic:)` on the [Transactions](/03-api-reference/02-mutations/01-transaction-mutations.md) page.

Expand Down Expand Up @@ -42,6 +42,36 @@ mutation CreateManagedWallet {
</TabItem>
</Tabs>

## SweepManagedWallet

Transfers **all** transferable tokens and ENJ out of a managed wallet to a single `recipient` in one call — the simplest way to migrate a player to a self-custodial wallet. Identify the wallet to empty with `signerExternalId` (or `signerAccount` for its public key); the work runs asynchronously and is rate-limited to once per hour per wallet. Returns `true` once the sweep is accepted.

See [Sweeping a Managed Wallet](/02-guides/01-platform/02-managing-users/03-using-managed-wallets.md#sweeping-a-managed-wallet) for the full walkthrough.

<Tabs>
<TabItem value="graphql" label="GraphQL">
```graphql
mutation SweepManagedWallet {
SweepManagedWallet(
network: ENJIN
chain: MATRIX
signerExternalId: "e73f9f38-6832-4822-922b-b9225245ba24"
recipient: "cxLf6yvvtscKrHRfKDphnzsT3eoRY45VbJvqXKub5pmj5mdbQ"
)
}
```
</TabItem>
<TabItem value="response" label="Response">
```json
{
"data": {
"SweepManagedWallet": true
}
}
```
</TabItem>
</Tabs>

:::tip Looking for the signing flow?
- For Wallet Daemon-signed transactions, see [`CreateTransaction`](/03-api-reference/02-mutations/01-transaction-mutations.md#createtransaction).
- For Managed Wallet-signed transactions, pass `signerAddress` or `signerExternalId` on `CreateTransaction`.
Expand Down
Loading