Skip to content

MsgSetOutgoingApproval creates or replaces one outgoing approval by ID without rebuilding the full approval list.

Creates or replaces a single outgoing approval for the signer in one collection. It is a wrapper around MsgUpdateUserApprovals that handles the list merge and versioning for you.

Example

bash
bb tx tokenization set-outgoing-approval 1 ./approval.json --from alice --chain-id bitbadges-1
ts
import { BitBadgesSigningClient, GenericCosmosAdapter, MsgSetOutgoingApproval } from 'bitbadges';

const adapter = await GenericCosmosAdapter.fromMnemonic(process.env.MNEMONIC!, 'bitbadges-1');
const client = new BitBadgesSigningClient({ adapter, network: 'mainnet' });

// alice lists token 5 for bob at 25 USDC, valid for 7 days, one use.
const msg = new MsgSetOutgoingApproval({
  creator: 'bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d',
  collectionId: 1n,
  approval: {
    toListId: 'bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue',
    initiatedByListId: 'bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue',
    transferTimes: [{ start: 1788739200000n, end: 1789344000000n }],
    tokenIds: [{ start: 5n, end: 5n }],
    ownershipTimes: [{ start: 1n, end: 18446744073709551615n }],
    uri: '',
    customData: '',
    approvalId: 'sell-token-5-to-bob',
    approvalCriteria: {
      merkleChallenges: [],
      predeterminedBalances: {
      },
      approvalAmounts: {
        overallApprovalAmount: 1n,
        perToAddressApprovalAmount: 0n,
        perFromAddressApprovalAmount: 0n,
        perInitiatedByAddressApprovalAmount: 0n,
        amountTrackerId: 'sell-token-5-to-bob',
        resetTimeIntervals: { startTime: 0n, intervalLength: 0n }
      },
      maxNumTransfers: {
        overallMaxNumTransfers: 1n,
        perToAddressMaxNumTransfers: 0n,
        perFromAddressMaxNumTransfers: 0n,
        perInitiatedByAddressMaxNumTransfers: 0n,
        amountTrackerId: 'sell-token-5-to-bob',
        resetTimeIntervals: { startTime: 0n, intervalLength: 0n }
      },
      coinTransfers: [
        {
          to: 'bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d',
          coins: [
            {
              denom: 'ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8',
              amount: 25000000n
            }
          ],
          overrideFromWithApproverAddress: false,
          overrideToWithInitiator: false
        }
      ],
      requireToEqualsInitiatedBy: false,
      requireToDoesNotEqualInitiatedBy: false,
      autoDeletionOptions: {
        afterOneUse: true,
        afterOverallMaxNumTransfers: false,
        allowCounterpartyPurge: false,
        allowPurgeIfExpired: false
      },
      mustOwnTokens: [],
      dynamicStoreChallenges: [],
      ethSignatureChallenges: [],
      recipientChecks: {
      },
      initiatorChecks: {
      },
      altTimeChecks: {
      },
      mustPrioritize: true,
      votingChallenges: [],
      evmQueryChallenges: []
    },
    version: 0n
  }
});

const result = await client.signAndBroadcast([msg]);
console.log(result.txHash, result.success);
import { BitBadgesSigningClient, GenericCosmosAdapter, MsgSetOutgoingApproval } from 'bitbadges';

const adapter = await GenericCosmosAdapter.fromMnemonic(process.env.MNEMONIC!, 'bitbadges-1');
const client = new BitBadgesSigningClient({ adapter, network: 'mainnet' });

// alice lists token 5 for bob at 25 USDC, valid for 7 days, one use.
const msg = new MsgSetOutgoingApproval({
  creator: 'bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d',
  collectionId: 1n,
  approval: {
    toListId: 'bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue',
    initiatedByListId: 'bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue',
    transferTimes: [{ start: 1788739200000n, end: 1789344000000n }],
    tokenIds: [{ start: 5n, end: 5n }],
    ownershipTimes: [{ start: 1n, end: 18446744073709551615n }],
    uri: '',
    customData: '',
    approvalId: 'sell-token-5-to-bob',
    approvalCriteria: {
      merkleChallenges: [],
      predeterminedBalances: {
        manualBalances: [],
        incrementedBalances: {
          startBalances: [],
          incrementTokenIdsBy: 0n,
          incrementOwnershipTimesBy: 0n,
          durationFromTimestamp: 0n,
          allowOverrideTimestamp: false,
          recurringOwnershipTimes: { startTime: 0n, intervalLength: 0n, chargePeriodLength: 0n },
          allowOverrideWithAnyValidToken: false,
          allowAmountScaling: false,
          maxScalingMultiplier: 0n
        },
        orderCalculationMethod: {
          useOverallNumTransfers: false,
          usePerToAddressNumTransfers: false,
          usePerFromAddressNumTransfers: false,
          usePerInitiatedByAddressNumTransfers: false,
          useMerkleChallengeLeafIndex: false,
          challengeTrackerId: ''
        }
      },
      approvalAmounts: {
        overallApprovalAmount: 1n,
        perToAddressApprovalAmount: 0n,
        perFromAddressApprovalAmount: 0n,
        perInitiatedByAddressApprovalAmount: 0n,
        amountTrackerId: 'sell-token-5-to-bob',
        resetTimeIntervals: { startTime: 0n, intervalLength: 0n }
      },
      maxNumTransfers: {
        overallMaxNumTransfers: 1n,
        perToAddressMaxNumTransfers: 0n,
        perFromAddressMaxNumTransfers: 0n,
        perInitiatedByAddressMaxNumTransfers: 0n,
        amountTrackerId: 'sell-token-5-to-bob',
        resetTimeIntervals: { startTime: 0n, intervalLength: 0n }
      },
      coinTransfers: [
        {
          to: 'bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d',
          coins: [
            {
              denom: 'ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8',
              amount: 25000000n
            }
          ],
          overrideFromWithApproverAddress: false,
          overrideToWithInitiator: false
        }
      ],
      requireToEqualsInitiatedBy: false,
      requireToDoesNotEqualInitiatedBy: false,
      autoDeletionOptions: {
        afterOneUse: true,
        afterOverallMaxNumTransfers: false,
        allowCounterpartyPurge: false,
        allowPurgeIfExpired: false
      },
      mustOwnTokens: [],
      dynamicStoreChallenges: [],
      ethSignatureChallenges: [],
      recipientChecks: {
        mustBeEvmContract: false,
        mustNotBeEvmContract: false,
        mustBeLiquidityPool: false,
        mustNotBeLiquidityPool: false
      },
      initiatorChecks: {
        mustBeEvmContract: false,
        mustNotBeEvmContract: false,
        mustBeLiquidityPool: false,
        mustNotBeLiquidityPool: false
      },
      altTimeChecks: {
        offlineHours: [],
        offlineDays: [],
        offlineMonths: [],
        offlineDaysOfMonth: [],
        offlineWeeksOfYear: [],
        timezoneOffsetMinutes: 0n,
        timezoneOffsetNegative: false
      },
      mustPrioritize: true,
      votingChallenges: [],
      evmQueryChallenges: []
    },
    version: 0n
  }
});

const result = await client.signAndBroadcast([msg]);
console.log(result.txHash, result.success);
json
{
  "creator": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d",
  "collectionId": "1",
  "approval": {
    "toListId": "bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue",
    "initiatedByListId": "bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue",
    "transferTimes": [{ "start": "1788739200000", "end": "1789344000000" }],
    "tokenIds": [{ "start": "5", "end": "5" }],
    "ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }],
    "approvalId": "sell-token-5-to-bob",
    "approvalCriteria": {
      "predeterminedBalances": {
        "incrementedBalances": {
          "recurringOwnershipTimes": { "startTime": "0", "intervalLength": "0", "chargePeriodLength": "0" }
        }
      },
      "approvalAmounts": {
        "overallApprovalAmount": "1",
        "amountTrackerId": "sell-token-5-to-bob",
        "resetTimeIntervals": { "startTime": "0", "intervalLength": "0" }
      },
      "maxNumTransfers": {
        "overallMaxNumTransfers": "1",
        "amountTrackerId": "sell-token-5-to-bob",
        "resetTimeIntervals": { "startTime": "0", "intervalLength": "0" }
      },
      "coinTransfers": [
        {
          "to": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d",
          "coins": [
            {
              "denom": "ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8",
              "amount": "25000000"
            }
          ]
        }
      ],
      "autoDeletionOptions": {
        "afterOneUse": true
      },
      "mustPrioritize": true
    }
  }
}
{
  "creator": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d",
  "collectionId": "1",
  "approval": {
    "toListId": "bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue",
    "initiatedByListId": "bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue",
    "transferTimes": [{ "start": "1788739200000", "end": "1789344000000" }],
    "tokenIds": [{ "start": "5", "end": "5" }],
    "ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }],
    "uri": "",
    "customData": "",
    "approvalId": "sell-token-5-to-bob",
    "approvalCriteria": {
      "merkleChallenges": [],
      "predeterminedBalances": {
        "manualBalances": [],
        "incrementedBalances": {
          "startBalances": [],
          "incrementTokenIdsBy": "0",
          "incrementOwnershipTimesBy": "0",
          "durationFromTimestamp": "0",
          "allowOverrideTimestamp": false,
          "recurringOwnershipTimes": { "startTime": "0", "intervalLength": "0", "chargePeriodLength": "0" },
          "allowOverrideWithAnyValidToken": false,
          "allowAmountScaling": false,
          "maxScalingMultiplier": "0"
        },
        "orderCalculationMethod": {
          "useOverallNumTransfers": false,
          "usePerToAddressNumTransfers": false,
          "usePerFromAddressNumTransfers": false,
          "usePerInitiatedByAddressNumTransfers": false,
          "useMerkleChallengeLeafIndex": false,
          "challengeTrackerId": ""
        }
      },
      "approvalAmounts": {
        "overallApprovalAmount": "1",
        "perToAddressApprovalAmount": "0",
        "perFromAddressApprovalAmount": "0",
        "perInitiatedByAddressApprovalAmount": "0",
        "amountTrackerId": "sell-token-5-to-bob",
        "resetTimeIntervals": { "startTime": "0", "intervalLength": "0" }
      },
      "maxNumTransfers": {
        "overallMaxNumTransfers": "1",
        "perToAddressMaxNumTransfers": "0",
        "perFromAddressMaxNumTransfers": "0",
        "perInitiatedByAddressMaxNumTransfers": "0",
        "amountTrackerId": "sell-token-5-to-bob",
        "resetTimeIntervals": { "startTime": "0", "intervalLength": "0" }
      },
      "coinTransfers": [
        {
          "to": "bb1p0rrel3365scadq5k9pv0x0zp9j22js6dnw70d",
          "coins": [
            {
              "denom": "ibc/E1116484B327AEE59CDC3DA73D319834781A13DB2A7DFC1F38A30CD45ABF58B8",
              "amount": "25000000"
            }
          ],
          "overrideFromWithApproverAddress": false,
          "overrideToWithInitiator": false
        }
      ],
      "requireToEqualsInitiatedBy": false,
      "requireToDoesNotEqualInitiatedBy": false,
      "autoDeletionOptions": {
        "afterOneUse": true,
        "afterOverallMaxNumTransfers": false,
        "allowCounterpartyPurge": false,
        "allowPurgeIfExpired": false
      },
      "mustOwnTokens": [],
      "dynamicStoreChallenges": [],
      "ethSignatureChallenges": [],
      "recipientChecks": {
        "mustBeEvmContract": false,
        "mustNotBeEvmContract": false,
        "mustBeLiquidityPool": false,
        "mustNotBeLiquidityPool": false
      },
      "initiatorChecks": {
        "mustBeEvmContract": false,
        "mustNotBeEvmContract": false,
        "mustBeLiquidityPool": false,
        "mustNotBeLiquidityPool": false
      },
      "altTimeChecks": {
        "offlineHours": [],
        "offlineDays": [],
        "offlineMonths": [],
        "offlineDaysOfMonth": [],
        "offlineWeeksOfYear": [],
        "timezoneOffsetMinutes": "0",
        "timezoneOffsetNegative": false
      },
      "mustPrioritize": true,
      "votingChallenges": [],
      "evmQueryChallenges": []
    },
    "version": "0"
  }
}

The set-outgoing-approval CLI command takes the approval object on its own, not the whole message. This approval has side effects (coinTransfers, trackers, auto-deletion), so mustPrioritize is true and bob must list it in prioritizedApprovals when he executes the transfer.

Ask your agent:

text
List token 5 of collection 1 for sale to bb1py4mfpg6uf59qkyzg0nmau322c5873eeysp5ue for 25 USDC.

Fields

FieldTypeRequiredDescription
creatorstringyesSigner. Users can only set their own approvals.
collectionIdUintyesCollection. "0" resolves to the most recently created collection.
approvalUserOutgoingApprovalyesThe approval to create or replace. Matched to an existing approval by approvalId. version is assigned by the chain; pass 0.

Response

FieldTypeDescription
actionstringcreated or edited.
versionstringVersion of the approval after the update.
reviewItemsstring[]Advisory notes.

Behavior

  • Loads the signer's current outgoing approvals (or the collection defaults), replaces the entry with the same approvalId or appends a new one, then runs the full MsgUpdateUserApprovals path with updateOutgoingApprovals: true.
  • A new approval starts at version 0. A changed approval gets an incremented version. An identical approval keeps its version and the response reports edited with the unchanged version.
  • The update is validated against the signer's canUpdateOutgoingApprovals permission and the collection's archived state.
  • Approvals that cannot be auto-scanned get mustPrioritize forced on.

Edit this page on GitHub