Portal’s Enclave MPC API supports token delegation operations across EVM and Solana chains. This guide covers building delegation transactions via the Client API and signing them with the Enclave MPC API.
Overview
The delegation endpoints allow you to:
- Approve other addresses to spend tokens on behalf of your wallet
- Revoke existing delegations to remove spending permissions
- Check status of active delegations and balances
- Transfer tokens as a delegate from another address
Prerequisites
Before using delegation operations, ensure you have:
Approving Delegations
Approving a delegation is a two-step process: build the unsigned transaction with the Client API, then sign and submit it with the Enclave MPC API.
Step 1: Build the Approval Transaction
Use POST /api/v3/clients/me/chains/:chain/assets/:token/approvals to build an unsigned approval transaction.
For complete API documentation, see the Client API reference.
curl --request POST \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/eip155:11155111/assets/USDC/approvals' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"delegateAddress": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"amount": "0.01"
}'
The response includes a transactions array with unsigned transaction objects:{
"transactions": [
{
"from": "0xa3e533c3df3c7cd9189c4578747c4448a295d22b",
"to": "0x1c7d4b196cb0c7b01d743fbc6116a902379c7238",
"data": "0x095ea7b3000000000000000000000000c74c4f7e330a62e0023f50b2b7b0491878fb4aa40000000000000000000000000000000000000000000000000000000000002710"
}
],
"metadata": {
"chainId": "eip155:11155111",
"ownerAddress": "0xa3e533c3df3c7cd9189c4578747c4448a295d22b",
"delegateAmount": "0.01",
"delegateAddress": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"tokenSymbol": "USDC"
}
}
curl --request POST \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/assets/USDC/approvals' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"delegateAddress": "7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"amount": "0.01"
}'
The response includes an encodedTransactions array with base64-encoded transactions:{
"encodedTransactions": [
"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIEC4lO3sml7OPCb2B7l24qng1cRm9J9aGqX+bt2ZRQnG/Is0RJBcOn7ZMos22MlvccAz+6hfOK3RzmBaeYNAJvGl3NFtEmNi3ankpovc/5QrK4ZTPvO7LJsTMyzacyiq5OBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKmvKeQuDyOC4uvNwTHJYrcdHOlP9zX9unzvI5P1JRmV3wEDAwECAAkEECcAAAAAAAA="
],
"metadata": {
"chainId": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"delegateAddress": "7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"delegateAmount": "0.01",
"delegateAmountRaw": "10000",
"lastValidBlockHeight": "434058739",
"ownerAddress": "n2vQ3c8emmQsjPRvLFaBVRv6UeTFXyDYa5MBRoY7QCN",
"serializedTransactionBase64Encoded": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIEC4lO3sml7OPCb2B7l24qng1cRm9J9aGqX+bt2ZRQnG/Is0RJBcOn7ZMos22MlvccAz+6hfOK3RzmBaeYNAJvGl3NFtEmNi3ankpovc/5QrK4ZTPvO7LJsTMyzacyiq5OBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKmvKeQuDyOC4uvNwTHJYrcdHOlP9zX9unzvI5P1JRmV3wEDAwECAAkEECcAAAAAAAA=",
"serializedTransactionBase58Encoded": "3T4DHUNXqSgNrtRMsDwQr7oG7756JXW4uNJ7x7RKJLTcSJRe6PqyR5fQffnXh4KTHs4MyRrDhR1K3zCeRrWsJBeoXxrwPvXaNz6ZYFY6Ci6qJYrcWiCoL8hGQJtwAAWE4EBz8mNL78DyJCbUp9rz3Wfyu2R8eY9VYzAQC9vhFqTgXHNMiNF31QPDh7K4nWSyvAuy5nbGUAGvKiYvNf4MDQoBnNPis6SnTzr2wPe8XKMePetZ29rqXbTvRWacnjA8w2DYbFyHiR5KT2ypN6UC6T6UkcGGAH467yCzTm2Q2B1MHAjAaMC4GY6DhUdZ4MPj2v8vf7RzQQST2f",
"tokenAccount": "EWT5sTcrawKJ73w5YXy9n2WD4uCo2UCEEkUi1potmP7P",
"tokenAddress": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
"tokenSymbol": "USDC",
"tokenDecimals": 6,
"unsignedTransactionMessage": {
"signatures": null,
"message": {
"accountKeys": [
"n2vQ3c8emmQsjPRvLFaBVRv6UeTFXyDYa5MBRoY7QCN",
"EWT5sTcrawKJ73w5YXy9n2WD4uCo2UCEEkUi1potmP7P",
"7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
],
"header": {
"numRequiredSignatures": 1,
"numReadonlySignedAccounts": 0,
"numReadonlyUnsignedAccounts": 2
},
"instructions": [
{
"programIdIndex": 3,
"accounts": [
1,
2,
0
],
"data": "3zynHDTKC8Du"
}
],
"recentBlockhash": "CnmPyBUhGgajDq8CbBAtBsfJWzeA5Zh9djmwRNgntMxr"
}
}
}
}
Step 2: Sign and Submit the Transaction
Use the Enclave MPC API to sign and submit the transaction returned in Step 1.
For complete API documentation, see the Enclave MPC API reference.
curl --request POST \
--url https://mpc-client.portalhq.io/v1/sign \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"share": "SECP256K1.share",
"method": "eth_sendTransaction",
"params": {
"from": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"to": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"data": "0x23b872dd000000000000000000000000a3e533c3df3c7cd9189c4578747c4448a295d22b000000000000000000000000c74c4f7e330a62e0023f50b2b7b0491878fb4aa40000000000000000000000000000000000000000000000000000000000002710",
"value": "0x0"
},
"rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/11155111",
"chainId": "eip155:11155111"
}'
curl --request POST \
--url https://mpc-client.portalhq.io/v1/sign \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"share": "ED25519.share",
"method": "sol_signAndSendTransaction",
"params": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAUHw3aL9Sv...",
"rpcUrl": "https://api.portalhq.io/rpc/v1/solana/EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"chainId": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
}'
Checking Delegation Status
Use GET /api/v3/clients/me/chains/:chain/assets/:token/delegations to check active delegations and token balances. This is a read-only call that does not require signing.
For complete API documentation, see the Client API reference.
curl --request GET \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/eip155:11155111/assets/USDC/delegations?delegateAddress=0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
The response includes the token balance and a list of active delegations:{
"balance": "0.0",
"balanceRaw": "0",
"chainId": "eip155:11155111",
"delegations": [
{
"address": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"delegateAmount": "0.01",
"delegateAmountRaw": "10000"
}
],
"token": "USDC",
"tokenAddress": "0x1c7d4b196cb0c7b01d743fbc6116a902379c7238"
}
curl --request GET \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/assets/USDC/delegations?delegateAddress=7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
The response includes the token balance and a list of active delegations:{
"balance": "0.000000",
"balanceRaw": "0",
"chainId": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"delegations": [
{
"address": "7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"delegateAmount": "0.010000",
"delegateAmountRaw": "10000"
}
],
"token": "USDC",
"tokenAddress": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
"tokenAccount": "2xMj47SeAfYnn6XwAktnJjabEfT4L4KEgddZUZ8FHvxc"
}
Revoking Delegations
Revoking follows the same two-step pattern: build the revocation transaction, then sign and submit it.
Step 1: Build the Revocation Transaction
Use POST /api/v3/clients/me/chains/:chain/assets/:token/revocations to build an unsigned revocation transaction.
For complete API documentation, see the Client API reference.
curl --request POST \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/eip155:11155111/assets/USDC/revocations' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"delegateAddress": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4"
}'
curl --request POST \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/assets/USDC/revocations' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"delegateAddress": "7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1"
}'
The response structure matches the approval response, returning transactions (EVM) or encodedTransactions (Solana).
Step 2: Sign and Submit the Transaction
Sign and submit the revocation transaction using the same Enclave MPC signing flow shown in the approval step.
For complete API documentation, see the Enclave MPC API reference.
Always revoke unused delegations after completing operations to minimize security risks.
Transferring as a Delegate
Once an owner has approved your address as a delegate, you can transfer tokens from their wallet to a destination address.
Step 1: Build the Transfer Transaction
Use POST /api/v3/clients/me/chains/:chain/assets/:token/delegations/transfers to build an unsigned transfer-as-delegate transaction.
For complete API documentation, see the Client API reference.
curl --request POST \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/eip155:11155111/assets/USDC/delegations/transfers' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"fromAddress": "0xa3e533c3df3c7cd9189c4578747c4448a295d22b",
"toAddress": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"amount": "0.01"
}'
The response includes the unsigned transaction(s) along with metadata about the transfer:{
"transactions": [
{
"from": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"to": "0x1c7d4b196cb0c7b01d743fbc6116a902379c7238",
"data": "0x23b872dd000000000000000000000000a3e533c3df3c7cd9189c4578747c4448a295d22b000000000000000000000000c74c4f7e330a62e0023f50b2b7b0491878fb4aa40000000000000000000000000000000000000000000000000000000000002710"
}
],
"metadata": {
"amount": "0.01",
"amountRaw": "10000",
"chainId": "eip155:11155111",
"delegateAddress": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"ownerAddress": "0xa3e533c3df3c7cd9189c4578747c4448a295d22b",
"recipientAddress": "0xc74c4f7e330a62e0023f50b2b7b0491878fb4aa4",
"tokenAddress": "0x1c7d4b196cb0c7b01d743fbc6116a902379c7238",
"tokenSymbol": "USDC",
"tokenDecimals": 6
}
}
curl --request POST \
--url 'https://api.portalhq.io/api/v3/clients/me/chains/solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/assets/USDC/delegations/transfers' \
--header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
--header 'Content-Type: application/json' \
--data '{
"fromAddress": "n2vQ3c8emmQsjPRvLFaBVRv6UeTFXyDYa5MBRoY7QCN",
"toAddress": "7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"amount": "0.01"
}'
The response includes an encodedTransactions array with base64-encoded transactions:{
"encodedTransactions": [
"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQHXc0W0SY2LdqeSmi9z/lCsrhlM+87ssmxMzLNpzKKrk7Is0RJBcOn7ZMos22MlvccAz+6hfOK3RzmBaeYNAJvGu3dgwf/7bDZTAAvIbI54fqs7ezz9zThi0kYkIaEhbfGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup4yXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKmVObR4y3ElZQoQnGi0XXe/r+pD1Xchw2XGx9IfjDnBNQIFBgACAAQDBgAGAwECAAkDECcAAAAAAAA="
],
"metadata": {
"amount": "0.01",
"amountRaw": "10000",
"chainId": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"delegateAddress": "7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"ownerAddress": "n2vQ3c8emmQsjPRvLFaBVRv6UeTFXyDYa5MBRoY7QCN",
"recipientAddress": "7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"tokenAddress": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
"tokenSymbol": "USDC",
"tokenDecimals": 6,
"needsRecipientTokenAccount": true,
"lastValidBlockHeight": "434059047",
"serializedTransactionBase64Encoded": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQHXc0W0SY2LdqeSmi9z/lCsrhlM+87ssmxMzLNpzKKrk7Is0RJBcOn7ZMos22MlvccAz+6hfOK3RzmBaeYNAJvGu3dgwf/7bDZTAAvIbI54fqs7ezz9zThi0kYkIaEhbfGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7RCyzkSFX8TqTPQE0KC0DK1/+zQGi2/G3eQYI3wAup4yXJY9OJInxuz0QKRSODYMLWhOZ2v8QhASOe9jb6fhZBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKmVObR4y3ElZQoQnGi0XXe/r+pD1Xchw2XGx9IfjDnBNQIFBgACAAQDBgAGAwECAAkDECcAAAAAAAA=",
"serializedTransactionBase58Encoded": "D8oZQdSemcrQBAEScyqQxo9zES3BszEVMppfay1AJAEfQrNuxXNAKCHtbhqGNQcvUKzNVTC8osiVbqtbiimLn8cnfqDFqtnEGsbsbvWXstVFxnHu9ZVtR8iSQqszkbZr4S2Lsisqehfzux3spSJogiYnsq4TwAfJ6Nc7XKLm3i8Qk9R7UP28CKtdoGQ7QDmaL9LiBDcWnhM19ZtNrRWPbySzDTke3hcnCQc9eRj89TVTiMJJEbi4MJ1eGDoXtusLdmA6pjxWS95Pyi2rCcQ31tpUMvXWa8iPXn1fFJKYmFrhaEvQXaF32tzQ4nqa7pdCUssrg4Rf6BemEg2P99MTFBasSxe6F5qV9Qwxt63R5JuoRmqy7zA5v1huM8UDcc5SQLcYFrr7z5FJphuyXu6k7MGQ8VzNphihSX2pa9FSLff6iRS8QZLS53UNZozNqVQ5MF5nJXnUtrxp97YM4esFRcV8vMZAf",
"unsignedTransactionMessage": {
"signatures": null,
"message": {
"accountKeys": [
"7KAJGeyLUdLXv9p7rFYpYUnX5Jac6CYMTuJSQr7FZzz1",
"EWT5sTcrawKJ73w5YXy9n2WD4uCo2UCEEkUi1potmP7P",
"H1XXmpUULrBxdNPELq3oAH6kQFaak8uCCVu3kxyQg7cy",
"11111111111111111111111111111111",
"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
],
"header": {
"numRequiredSignatures": 1,
"numReadonlySignedAccounts": 0,
"numReadonlyUnsignedAccounts": 4
},
"instructions": [
{
"programIdIndex": 5,
"accounts": [
0,
2,
0,
4,
3,
6
],
"data": ""
},
{
"programIdIndex": 6,
"accounts": [
1,
2,
0
],
"data": "3GAG5eogvTjV"
}
],
"recentBlockhash": "B3WnL5RxXxi4TXE5cSQJHkErsqjr1QQRJSiAycidYWWQ"
}
}
}
}
Step 2: Sign and Submit the Transaction
Sign and submit the transfer transaction using the same Enclave MPC signing flow shown in the approval step.
For complete API documentation, see the Enclave MPC API reference.
Delegation Roles: fromAddress is the token owner who approved the delegation. Your wallet (the delegate) signs the transaction to transfer tokens from the owner to the toAddress recipient.
Supported Networks
Delegations work on all Portal-supported EVM and Solana chains:
- EVM: Ethereum, Polygon, Base, Arbitrum, Optimism, and all other EVM-compatible chains
- Solana: Solana Mainnet and Devnet
For a complete list, see Blockchain Support.
Next Steps