@mysten/sui 2.30.0 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/bcs/bcs.d.mts +6 -6
  3. package/dist/bcs/bcs.d.mts.map +1 -1
  4. package/dist/bcs/bcs.mjs +5 -1
  5. package/dist/bcs/bcs.mjs.map +1 -1
  6. package/dist/bcs/index.d.mts +103 -11
  7. package/dist/bcs/index.d.mts.map +1 -1
  8. package/dist/bcs/types.d.mts.map +1 -1
  9. package/dist/client/core-resolver.mjs +2 -1
  10. package/dist/client/core-resolver.mjs.map +1 -1
  11. package/dist/client/transaction-resolver.mjs +35 -8
  12. package/dist/client/transaction-resolver.mjs.map +1 -1
  13. package/dist/cryptography/signature.d.mts +6 -6
  14. package/dist/graphql/generated/tada-env.d.mts +74 -0
  15. package/dist/grpc/proto/sui/rpc/v2/input.d.mts +21 -1
  16. package/dist/grpc/proto/sui/rpc/v2/input.d.mts.map +1 -1
  17. package/dist/grpc/proto/sui/rpc/v2/input.mjs +21 -0
  18. package/dist/grpc/proto/sui/rpc/v2/input.mjs.map +1 -1
  19. package/dist/grpc/proto/sui/rpc/v2/ledger_service.client.d.mts +4 -4
  20. package/dist/grpc/proto/sui/rpc/v2/move_package_service.client.d.mts +4 -4
  21. package/dist/grpc/proto/sui/rpc/v2/name_service.client.d.mts +4 -4
  22. package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.client.d.mts +4 -4
  23. package/dist/grpc/proto/sui/rpc/v2/state_service.client.d.mts +4 -4
  24. package/dist/grpc/proto/sui/rpc/v2/subscription_service.client.d.mts +4 -4
  25. package/dist/grpc/proto/sui/rpc/v2/transaction_execution_service.client.d.mts +4 -4
  26. package/dist/jsonRpc/core.mjs +1 -1
  27. package/dist/jsonRpc/core.mjs.map +1 -1
  28. package/dist/transactions/Transaction.d.mts +44 -39
  29. package/dist/transactions/Transaction.d.mts.map +1 -1
  30. package/dist/transactions/Transaction.mjs +65 -24
  31. package/dist/transactions/Transaction.mjs.map +1 -1
  32. package/dist/transactions/data/internal.d.mts +12 -0
  33. package/dist/transactions/data/internal.d.mts.map +1 -1
  34. package/dist/transactions/data/internal.mjs +5 -1
  35. package/dist/transactions/data/internal.mjs.map +1 -1
  36. package/dist/transactions/data/v2.d.mts +5 -0
  37. package/dist/transactions/data/v2.d.mts.map +1 -1
  38. package/dist/transactions/index.d.mts +3 -2
  39. package/dist/transactions/intents/AllowanceBalance.mjs +147 -0
  40. package/dist/transactions/intents/AllowanceBalance.mjs.map +1 -0
  41. package/dist/transactions/intents/BalanceIntentNames.mjs +7 -0
  42. package/dist/transactions/intents/BalanceIntentNames.mjs.map +1 -0
  43. package/dist/transactions/intents/BalanceOptions.d.mts +27 -0
  44. package/dist/transactions/intents/BalanceOptions.d.mts.map +1 -0
  45. package/dist/transactions/intents/BalanceOptions.mjs +12 -0
  46. package/dist/transactions/intents/BalanceOptions.mjs.map +1 -0
  47. package/dist/transactions/intents/CoinWithBalance.d.mts.map +1 -1
  48. package/dist/transactions/intents/CoinWithBalance.mjs +31 -10
  49. package/dist/transactions/intents/CoinWithBalance.mjs.map +1 -1
  50. package/dist/transactions/intents/ResolveBalances.mjs +16 -0
  51. package/dist/transactions/intents/ResolveBalances.mjs.map +1 -0
  52. package/dist/transactions/resolve.d.mts.map +1 -1
  53. package/dist/transactions/resolve.mjs +1 -1
  54. package/dist/transactions/resolve.mjs.map +1 -1
  55. package/dist/version.mjs +1 -1
  56. package/dist/version.mjs.map +1 -1
  57. package/dist/zklogin/bcs.d.mts +14 -14
  58. package/docs/llms-index.md +1 -0
  59. package/docs/transactions/allowances.md +176 -0
  60. package/docs/transactions/coins-and-balances.md +12 -9
  61. package/package.json +1 -1
  62. package/src/bcs/bcs.ts +4 -0
  63. package/src/bcs/types.ts +2 -1
  64. package/src/client/core-resolver.ts +6 -4
  65. package/src/client/transaction-resolver.ts +43 -9
  66. package/src/graphql/generated/schema.graphql +87 -42
  67. package/src/graphql/generated/tada-env.ts +84 -0
  68. package/src/grpc/proto/sui/rpc/v2/input.ts +22 -0
  69. package/src/jsonRpc/core.ts +3 -4
  70. package/src/transactions/Transaction.ts +70 -49
  71. package/src/transactions/data/internal.ts +4 -0
  72. package/src/transactions/index.ts +3 -0
  73. package/src/transactions/intents/AllowanceBalance.ts +204 -0
  74. package/src/transactions/intents/BalanceIntentNames.ts +5 -0
  75. package/src/transactions/intents/BalanceOptions.ts +45 -0
  76. package/src/transactions/intents/CoinWithBalance.ts +51 -8
  77. package/src/transactions/intents/ResolveBalances.ts +30 -0
  78. package/src/transactions/resolve.ts +6 -0
  79. package/src/version.ts +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResolveBalances.mjs","names":[],"sources":["../../../src/transactions/intents/ResolveBalances.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { IntentResolverOptions } from '../resolve.js';\nimport type { TransactionDataBuilder } from '../TransactionData.js';\nimport { ALLOWANCE_BALANCE, COIN_WITH_BALANCE } from './BalanceIntentNames.js';\nimport { resolveAllowanceBalance } from './AllowanceBalance.js';\nimport { resolveCoinBalance } from './CoinWithBalance.js';\n\nexport async function resolveBalances(\n\ttransactionData: TransactionDataBuilder,\n\toptions: IntentResolverOptions,\n\tnext: () => Promise<void>,\n) {\n\tconst intents = new Set(options.intentNames ?? [ALLOWANCE_BALANCE, COIN_WITH_BALANCE]);\n\tconst shouldResolve = (name: string) =>\n\t\tintents.has(name) &&\n\t\t!options.supportedIntents?.includes(name) &&\n\t\ttransactionData.commands.some((command) => command.$Intent?.name === name);\n\n\t// Reserve allowance withdrawals before ordinary coin selection, including when\n\t// the sender is also the funder. Keep separate intents for wallet negotiation.\n\tif (shouldResolve(ALLOWANCE_BALANCE)) {\n\t\tawait resolveAllowanceBalance(transactionData, options, async () => {});\n\t}\n\tif (shouldResolve(COIN_WITH_BALANCE)) {\n\t\tawait resolveCoinBalance(transactionData, options, async () => {});\n\t}\n\tawait next();\n}\n"],"mappings":";;;;;AASA,eAAsB,gBACrB,iBACA,SACA,MACC;CACD,MAAM,UAAU,IAAI,IAAI,QAAQ,eAAe,CAAC,mBAAmB,kBAAkB,CAAC;CACtF,MAAM,iBAAiB,SACtB,QAAQ,IAAI,KAAK,IACjB,CAAC,QAAQ,kBAAkB,SAAS,KAAK,IACzC,gBAAgB,SAAS,MAAM,YAAY,QAAQ,SAAS,SAAS,KAAK;AAI3E,KAAI,cAAc,kBAAkB,CACnC,OAAM,wBAAwB,iBAAiB,SAAS,YAAY,GAAG;AAExE,KAAI,cAAc,kBAAkB,CACnC,OAAM,mBAAmB,iBAAiB,SAAS,YAAY,GAAG;AAEnE,OAAM,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.mts","names":[],"sources":["../../src/transactions/resolve.ts"],"mappings":";;;;;UAaiB,uBAAA;EAChB,MAAA,GAAS,iBAAA;EACT,mBAAA;EAFgB;;;;;;;EAUhB,+BAAA;AAAA;AAAA,UAGgB,2BAAA,SAAoC,uBAAA;EACpD,gBAAA;AAAA;AAAA,KAGW,iBAAA,IACX,eAAA,EAAiB,sBAAA,EACjB,OAAA,EAAS,uBAAA,EACT,IAAA,QAAY,OAAA,WACR,OAAA"}
1
+ {"version":3,"file":"resolve.d.mts","names":[],"sources":["../../src/transactions/resolve.ts"],"mappings":";;;;;UAaiB,uBAAA;EAChB,MAAA,GAAS,iBAAA;EACT,mBAAA;EAFgB;;;;;;;EAUhB,+BAAA;AAAA;AAAA,UAGgB,2BAAA,SAAoC,uBAAA;EACpD,gBAAA;AAAA;AAAA,KASW,iBAAA,IACX,eAAA,EAAiB,sBAAA,EACjB,OAAA,EAAS,uBAAA,EACT,IAAA,QAAY,OAAA,WACR,OAAA"}
@@ -57,5 +57,5 @@ function normalizeRawArgument(arg, schema, transactionData) {
57
57
  }
58
58
 
59
59
  //#endregion
60
- export { needsTransactionResolution, resolveTransactionPlugin };
60
+ export { getClient, needsTransactionResolution, resolveTransactionPlugin };
61
61
  //# sourceMappingURL=resolve.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.mjs","names":["bcs"],"sources":["../../src/transactions/resolve.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Argument } from './data/internal.js';\n\nimport type { ClientWithCoreApi } from '../client/index.js';\nimport type { TransactionDataBuilder } from './TransactionData.js';\nimport type { BcsType } from '@mysten/bcs';\nimport { Inputs } from './Inputs.js';\nimport { bcs } from '../bcs/index.js';\nimport { coreClientResolveTransactionPlugin } from '../client/core-resolver.js';\nimport { transactionUsesGasCoin } from './resolution-utils.js';\n\nexport interface BuildTransactionOptions {\n\tclient?: ClientWithCoreApi;\n\tonlyTransactionKind?: boolean;\n\t/**\n\t * Resolve `CoinWithBalance` intents from address balance without looking up balances or coins.\n\t *\n\t * If nothing else needs resolution, the transaction doesn't use `GasCoin`, and it already has a\n\t * `ValidDuring` or `Validity` expiration, an unset gas payment is also set to `[]` (pay gas from\n\t * address balance). Execution fails if the balances aren't there.\n\t */\n\tassumeSufficientAddressBalances?: boolean;\n}\n\nexport interface SerializeTransactionOptions extends BuildTransactionOptions {\n\tsupportedIntents?: string[];\n}\n\nexport type TransactionPlugin = (\n\ttransactionData: TransactionDataBuilder,\n\toptions: BuildTransactionOptions,\n\tnext: () => Promise<void>,\n) => Promise<void>;\n\nexport function needsTransactionResolution(\n\tdata: TransactionDataBuilder,\n\toptions: BuildTransactionOptions,\n): boolean {\n\tif (\n\t\tdata.inputs.some((input) => {\n\t\t\treturn input.UnresolvedObject || input.UnresolvedPure;\n\t\t})\n\t) {\n\t\treturn true;\n\t}\n\n\tif (!options.onlyTransactionKind) {\n\t\tif (!data.gasData.price || !data.gasData.budget) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (!data.gasData.payment) {\n\t\t\tconst assumesAddressBalanceGas =\n\t\t\t\toptions.assumeSufficientAddressBalances && !transactionUsesGasCoin(data);\n\n\t\t\t// Address balance gas has no object version to protect against replay, so an offline build\n\t\t\t// needs a ValidDuring expiration. Epoch expiration doesn't count.\n\t\t\tif (\n\t\t\t\t!assumesAddressBalanceGas ||\n\t\t\t\t(data.expiration?.$kind !== 'ValidDuring' && data.expiration?.$kind !== 'Validity')\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (data.gasData.payment.length === 0 && !data.expiration) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport async function resolveTransactionPlugin(\n\ttransactionData: TransactionDataBuilder,\n\toptions: BuildTransactionOptions,\n\tnext: () => Promise<void>,\n) {\n\tnormalizeRawArguments(transactionData);\n\n\tif (!needsTransactionResolution(transactionData, options)) {\n\t\t// Payment can only be unset here when assumeSufficientAddressBalances applies\n\t\tif (!options.onlyTransactionKind && !transactionData.gasData.payment) {\n\t\t\ttransactionData.gasData.payment = [];\n\t\t}\n\n\t\tawait validate(transactionData);\n\t\treturn next();\n\t}\n\n\tconst client = getClient(options);\n\tconst plugin = client.core?.resolveTransactionPlugin() ?? coreClientResolveTransactionPlugin;\n\n\treturn plugin(transactionData, options, async () => {\n\t\tawait validate(transactionData);\n\t\tawait next();\n\t});\n}\n\nfunction validate(transactionData: TransactionDataBuilder) {\n\ttransactionData.inputs.forEach((input, index) => {\n\t\tif (input.$kind !== 'Object' && input.$kind !== 'Pure' && input.$kind !== 'FundsWithdrawal') {\n\t\t\tthrow new Error(\n\t\t\t\t`Input at index ${index} has not been resolved. Expected a Pure, Object, or FundsWithdrawal input, but found ${JSON.stringify(\n\t\t\t\t\tinput,\n\t\t\t\t)}`,\n\t\t\t);\n\t\t}\n\t});\n}\n\nexport function getClient(options: BuildTransactionOptions) {\n\tif (!options.client) {\n\t\tthrow new Error(\n\t\t\t`No sui client passed to Transaction#build, but transaction data was not sufficient to build offline.`,\n\t\t);\n\t}\n\n\treturn options.client;\n}\n\nfunction normalizeRawArguments(transactionData: TransactionDataBuilder) {\n\tfor (const command of transactionData.commands) {\n\t\tswitch (command.$kind) {\n\t\t\tcase 'SplitCoins':\n\t\t\t\tcommand.SplitCoins.amounts.forEach((amount) => {\n\t\t\t\t\tnormalizeRawArgument(amount, bcs.U64, transactionData);\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase 'TransferObjects':\n\t\t\t\tnormalizeRawArgument(command.TransferObjects.address, bcs.Address, transactionData);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\nfunction normalizeRawArgument(\n\targ: Argument,\n\tschema: BcsType<any>,\n\ttransactionData: TransactionDataBuilder,\n) {\n\tif (arg.$kind !== 'Input') {\n\t\treturn;\n\t}\n\tconst input = transactionData.inputs[arg.Input];\n\n\tif (input.$kind !== 'UnresolvedPure') {\n\t\treturn;\n\t}\n\n\ttransactionData.inputs[arg.Input] = Inputs.Pure(schema.serialize(input.UnresolvedPure.value));\n}\n"],"mappings":";;;;;;AAoCA,SAAgB,2BACf,MACA,SACU;AACV,KACC,KAAK,OAAO,MAAM,UAAU;AAC3B,SAAO,MAAM,oBAAoB,MAAM;GACtC,CAEF,QAAO;AAGR,KAAI,CAAC,QAAQ,qBAAqB;AACjC,MAAI,CAAC,KAAK,QAAQ,SAAS,CAAC,KAAK,QAAQ,OACxC,QAAO;AAGR,MAAI,CAAC,KAAK,QAAQ,SAMjB;OACC,EALA,QAAQ,mCAAmC,CAAC,uBAAuB,KAAK,KAMvE,KAAK,YAAY,UAAU,iBAAiB,KAAK,YAAY,UAAU,WAExE,QAAO;aAEE,KAAK,QAAQ,QAAQ,WAAW,KAAK,CAAC,KAAK,WACrD,QAAO;;AAIT,QAAO;;AAGR,eAAsB,yBACrB,iBACA,SACA,MACC;AACD,uBAAsB,gBAAgB;AAEtC,KAAI,CAAC,2BAA2B,iBAAiB,QAAQ,EAAE;AAE1D,MAAI,CAAC,QAAQ,uBAAuB,CAAC,gBAAgB,QAAQ,QAC5D,iBAAgB,QAAQ,UAAU,EAAE;AAGrC,QAAM,SAAS,gBAAgB;AAC/B,SAAO,MAAM;;AAMd,SAHe,UAAU,QAAQ,CACX,MAAM,0BAA0B,IAAI,oCAE5C,iBAAiB,SAAS,YAAY;AACnD,QAAM,SAAS,gBAAgB;AAC/B,QAAM,MAAM;GACX;;AAGH,SAAS,SAAS,iBAAyC;AAC1D,iBAAgB,OAAO,SAAS,OAAO,UAAU;AAChD,MAAI,MAAM,UAAU,YAAY,MAAM,UAAU,UAAU,MAAM,UAAU,kBACzE,OAAM,IAAI,MACT,kBAAkB,MAAM,wFAAwF,KAAK,UACpH,MACA,GACD;GAED;;AAGH,SAAgB,UAAU,SAAkC;AAC3D,KAAI,CAAC,QAAQ,OACZ,OAAM,IAAI,MACT,uGACA;AAGF,QAAO,QAAQ;;AAGhB,SAAS,sBAAsB,iBAAyC;AACvE,MAAK,MAAM,WAAW,gBAAgB,SACrC,SAAQ,QAAQ,OAAhB;EACC,KAAK;AACJ,WAAQ,WAAW,QAAQ,SAAS,WAAW;AAC9C,yBAAqB,QAAQA,OAAI,KAAK,gBAAgB;KACrD;AACF;EACD,KAAK;AACJ,wBAAqB,QAAQ,gBAAgB,SAASA,OAAI,SAAS,gBAAgB;AACnF;;;AAKJ,SAAS,qBACR,KACA,QACA,iBACC;AACD,KAAI,IAAI,UAAU,QACjB;CAED,MAAM,QAAQ,gBAAgB,OAAO,IAAI;AAEzC,KAAI,MAAM,UAAU,iBACnB;AAGD,iBAAgB,OAAO,IAAI,SAAS,OAAO,KAAK,OAAO,UAAU,MAAM,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"resolve.mjs","names":["bcs"],"sources":["../../src/transactions/resolve.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Argument } from './data/internal.js';\n\nimport type { ClientWithCoreApi } from '../client/index.js';\nimport type { TransactionDataBuilder } from './TransactionData.js';\nimport type { BcsType } from '@mysten/bcs';\nimport { Inputs } from './Inputs.js';\nimport { bcs } from '../bcs/index.js';\nimport { coreClientResolveTransactionPlugin } from '../client/core-resolver.js';\nimport { transactionUsesGasCoin } from './resolution-utils.js';\n\nexport interface BuildTransactionOptions {\n\tclient?: ClientWithCoreApi;\n\tonlyTransactionKind?: boolean;\n\t/**\n\t * Resolve `CoinWithBalance` intents from address balance without looking up balances or coins.\n\t *\n\t * If nothing else needs resolution, the transaction doesn't use `GasCoin`, and it already has a\n\t * `ValidDuring` or `Validity` expiration, an unset gas payment is also set to `[]` (pay gas from\n\t * address balance). Execution fails if the balances aren't there.\n\t */\n\tassumeSufficientAddressBalances?: boolean;\n}\n\nexport interface SerializeTransactionOptions extends BuildTransactionOptions {\n\tsupportedIntents?: string[];\n}\n\n/** Options supplied when a registered intent resolver runs. */\nexport interface IntentResolverOptions extends SerializeTransactionOptions {\n\t/** Intent names assigned to this resolver for this serialization pass. */\n\tintentNames?: readonly string[];\n}\n\nexport type TransactionPlugin = (\n\ttransactionData: TransactionDataBuilder,\n\toptions: BuildTransactionOptions,\n\tnext: () => Promise<void>,\n) => Promise<void>;\n\nexport function needsTransactionResolution(\n\tdata: TransactionDataBuilder,\n\toptions: BuildTransactionOptions,\n): boolean {\n\tif (\n\t\tdata.inputs.some((input) => {\n\t\t\treturn input.UnresolvedObject || input.UnresolvedPure;\n\t\t})\n\t) {\n\t\treturn true;\n\t}\n\n\tif (!options.onlyTransactionKind) {\n\t\tif (!data.gasData.price || !data.gasData.budget) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (!data.gasData.payment) {\n\t\t\tconst assumesAddressBalanceGas =\n\t\t\t\toptions.assumeSufficientAddressBalances && !transactionUsesGasCoin(data);\n\n\t\t\t// Address balance gas has no object version to protect against replay, so an offline build\n\t\t\t// needs a ValidDuring expiration. Epoch expiration doesn't count.\n\t\t\tif (\n\t\t\t\t!assumesAddressBalanceGas ||\n\t\t\t\t(data.expiration?.$kind !== 'ValidDuring' && data.expiration?.$kind !== 'Validity')\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (data.gasData.payment.length === 0 && !data.expiration) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport async function resolveTransactionPlugin(\n\ttransactionData: TransactionDataBuilder,\n\toptions: BuildTransactionOptions,\n\tnext: () => Promise<void>,\n) {\n\tnormalizeRawArguments(transactionData);\n\n\tif (!needsTransactionResolution(transactionData, options)) {\n\t\t// Payment can only be unset here when assumeSufficientAddressBalances applies\n\t\tif (!options.onlyTransactionKind && !transactionData.gasData.payment) {\n\t\t\ttransactionData.gasData.payment = [];\n\t\t}\n\n\t\tawait validate(transactionData);\n\t\treturn next();\n\t}\n\n\tconst client = getClient(options);\n\tconst plugin = client.core?.resolveTransactionPlugin() ?? coreClientResolveTransactionPlugin;\n\n\treturn plugin(transactionData, options, async () => {\n\t\tawait validate(transactionData);\n\t\tawait next();\n\t});\n}\n\nfunction validate(transactionData: TransactionDataBuilder) {\n\ttransactionData.inputs.forEach((input, index) => {\n\t\tif (input.$kind !== 'Object' && input.$kind !== 'Pure' && input.$kind !== 'FundsWithdrawal') {\n\t\t\tthrow new Error(\n\t\t\t\t`Input at index ${index} has not been resolved. Expected a Pure, Object, or FundsWithdrawal input, but found ${JSON.stringify(\n\t\t\t\t\tinput,\n\t\t\t\t)}`,\n\t\t\t);\n\t\t}\n\t});\n}\n\nexport function getClient(options: BuildTransactionOptions) {\n\tif (!options.client) {\n\t\tthrow new Error(\n\t\t\t`No sui client passed to Transaction#build, but transaction data was not sufficient to build offline.`,\n\t\t);\n\t}\n\n\treturn options.client;\n}\n\nfunction normalizeRawArguments(transactionData: TransactionDataBuilder) {\n\tfor (const command of transactionData.commands) {\n\t\tswitch (command.$kind) {\n\t\t\tcase 'SplitCoins':\n\t\t\t\tcommand.SplitCoins.amounts.forEach((amount) => {\n\t\t\t\t\tnormalizeRawArgument(amount, bcs.U64, transactionData);\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase 'TransferObjects':\n\t\t\t\tnormalizeRawArgument(command.TransferObjects.address, bcs.Address, transactionData);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\nfunction normalizeRawArgument(\n\targ: Argument,\n\tschema: BcsType<any>,\n\ttransactionData: TransactionDataBuilder,\n) {\n\tif (arg.$kind !== 'Input') {\n\t\treturn;\n\t}\n\tconst input = transactionData.inputs[arg.Input];\n\n\tif (input.$kind !== 'UnresolvedPure') {\n\t\treturn;\n\t}\n\n\ttransactionData.inputs[arg.Input] = Inputs.Pure(schema.serialize(input.UnresolvedPure.value));\n}\n"],"mappings":";;;;;;AA0CA,SAAgB,2BACf,MACA,SACU;AACV,KACC,KAAK,OAAO,MAAM,UAAU;AAC3B,SAAO,MAAM,oBAAoB,MAAM;GACtC,CAEF,QAAO;AAGR,KAAI,CAAC,QAAQ,qBAAqB;AACjC,MAAI,CAAC,KAAK,QAAQ,SAAS,CAAC,KAAK,QAAQ,OACxC,QAAO;AAGR,MAAI,CAAC,KAAK,QAAQ,SAMjB;OACC,EALA,QAAQ,mCAAmC,CAAC,uBAAuB,KAAK,KAMvE,KAAK,YAAY,UAAU,iBAAiB,KAAK,YAAY,UAAU,WAExE,QAAO;aAEE,KAAK,QAAQ,QAAQ,WAAW,KAAK,CAAC,KAAK,WACrD,QAAO;;AAIT,QAAO;;AAGR,eAAsB,yBACrB,iBACA,SACA,MACC;AACD,uBAAsB,gBAAgB;AAEtC,KAAI,CAAC,2BAA2B,iBAAiB,QAAQ,EAAE;AAE1D,MAAI,CAAC,QAAQ,uBAAuB,CAAC,gBAAgB,QAAQ,QAC5D,iBAAgB,QAAQ,UAAU,EAAE;AAGrC,QAAM,SAAS,gBAAgB;AAC/B,SAAO,MAAM;;AAMd,SAHe,UAAU,QAAQ,CACX,MAAM,0BAA0B,IAAI,oCAE5C,iBAAiB,SAAS,YAAY;AACnD,QAAM,SAAS,gBAAgB;AAC/B,QAAM,MAAM;GACX;;AAGH,SAAS,SAAS,iBAAyC;AAC1D,iBAAgB,OAAO,SAAS,OAAO,UAAU;AAChD,MAAI,MAAM,UAAU,YAAY,MAAM,UAAU,UAAU,MAAM,UAAU,kBACzE,OAAM,IAAI,MACT,kBAAkB,MAAM,wFAAwF,KAAK,UACpH,MACA,GACD;GAED;;AAGH,SAAgB,UAAU,SAAkC;AAC3D,KAAI,CAAC,QAAQ,OACZ,OAAM,IAAI,MACT,uGACA;AAGF,QAAO,QAAQ;;AAGhB,SAAS,sBAAsB,iBAAyC;AACvE,MAAK,MAAM,WAAW,gBAAgB,SACrC,SAAQ,QAAQ,OAAhB;EACC,KAAK;AACJ,WAAQ,WAAW,QAAQ,SAAS,WAAW;AAC9C,yBAAqB,QAAQA,OAAI,KAAK,gBAAgB;KACrD;AACF;EACD,KAAK;AACJ,wBAAqB,QAAQ,gBAAgB,SAASA,OAAI,SAAS,gBAAgB;AACnF;;;AAKJ,SAAS,qBACR,KACA,QACA,iBACC;AACD,KAAI,IAAI,UAAU,QACjB;CAED,MAAM,QAAQ,gBAAgB,OAAO,IAAI;AAEzC,KAAI,MAAM,UAAU,iBACnB;AAGD,iBAAgB,OAAO,IAAI,SAAS,OAAO,KAAK,OAAO,UAAU,MAAM,eAAe,MAAM,CAAC"}
package/dist/version.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/version.ts
2
- const PACKAGE_VERSION = "2.30.0";
2
+ const PACKAGE_VERSION = "2.31.0";
3
3
 
4
4
  //#endregion
5
5
  export { PACKAGE_VERSION };
@@ -1 +1 @@
1
- {"version":3,"file":"version.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n// This file is generated by genversion.mjs. Do not edit it directly.\n\nexport const PACKAGE_VERSION = '2.30.0';\n"],"mappings":";AAKA,MAAa,kBAAkB"}
1
+ {"version":3,"file":"version.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n// This file is generated by genversion.mjs. Do not edit it directly.\n\nexport const PACKAGE_VERSION = '2.31.0';\n"],"mappings":";AAKA,MAAa,kBAAkB"}
@@ -1,31 +1,31 @@
1
- import * as _mysten_bcs1238 from "@mysten/bcs";
1
+ import * as _mysten_bcs1384 from "@mysten/bcs";
2
2
  import { InferBcsInput } from "@mysten/bcs";
3
3
 
4
4
  //#region src/zklogin/bcs.d.ts
5
- declare const zkLoginSignature: _mysten_bcs1238.BcsStruct<{
6
- inputs: _mysten_bcs1238.BcsStruct<{
7
- proofPoints: _mysten_bcs1238.BcsStruct<{
8
- a: _mysten_bcs1238.BcsType<string[], Iterable<string> & {
5
+ declare const zkLoginSignature: _mysten_bcs1384.BcsStruct<{
6
+ inputs: _mysten_bcs1384.BcsStruct<{
7
+ proofPoints: _mysten_bcs1384.BcsStruct<{
8
+ a: _mysten_bcs1384.BcsType<string[], Iterable<string> & {
9
9
  length: number;
10
10
  }, string>;
11
- b: _mysten_bcs1238.BcsType<string[][], Iterable<Iterable<string> & {
11
+ b: _mysten_bcs1384.BcsType<string[][], Iterable<Iterable<string> & {
12
12
  length: number;
13
13
  }> & {
14
14
  length: number;
15
15
  }, string>;
16
- c: _mysten_bcs1238.BcsType<string[], Iterable<string> & {
16
+ c: _mysten_bcs1384.BcsType<string[], Iterable<string> & {
17
17
  length: number;
18
18
  }, string>;
19
19
  }, string>;
20
- issBase64Details: _mysten_bcs1238.BcsStruct<{
21
- value: _mysten_bcs1238.BcsType<string, string, "string">;
22
- indexMod4: _mysten_bcs1238.BcsType<number, number, "u8">;
20
+ issBase64Details: _mysten_bcs1384.BcsStruct<{
21
+ value: _mysten_bcs1384.BcsType<string, string, "string">;
22
+ indexMod4: _mysten_bcs1384.BcsType<number, number, "u8">;
23
23
  }, string>;
24
- headerBase64: _mysten_bcs1238.BcsType<string, string, "string">;
25
- addressSeed: _mysten_bcs1238.BcsType<string, string, "string">;
24
+ headerBase64: _mysten_bcs1384.BcsType<string, string, "string">;
25
+ addressSeed: _mysten_bcs1384.BcsType<string, string, "string">;
26
26
  }, string>;
27
- maxEpoch: _mysten_bcs1238.BcsType<string, string | number | bigint, "u64">;
28
- userSignature: _mysten_bcs1238.BcsType<Uint8Array<ArrayBufferLike>, Iterable<number>, "vector<u8>">;
27
+ maxEpoch: _mysten_bcs1384.BcsType<string, string | number | bigint, "u64">;
28
+ userSignature: _mysten_bcs1384.BcsType<Uint8Array<ArrayBufferLike>, Iterable<number>, "vector<u8>">;
29
29
  }, string>;
30
30
  type ZkLoginSignature = InferBcsInput<typeof zkLoginSignature>;
31
31
  type ZkLoginSignatureInputs = ZkLoginSignature['inputs'];
@@ -12,6 +12,7 @@
12
12
  - [Building Transactions](./transactions/basics.md): Construct programmable transaction blocks with the Transaction API
13
13
  - [Signing and Execution](./transactions/signing-and-execution.md): Sign transactions and execute them on the Sui network
14
14
  - [Coins and Balances](./transactions/coins-and-balances.md): Work with coin objects and address balances in transactions
15
+ - [Allowances](./transactions/allowances.md): Create allowances and spend from another account's address balance
15
16
  - [Commands and Inputs Reference](./transactions/reference.md): Complete reference for transaction commands and input types
16
17
  - [Building Offline](./transactions/offline.md): Build transactions without a network connection
17
18
  - [Cryptography](./cryptography.md): >- Sign and verify Sui transactions and messages with keypairs and external signers
@@ -0,0 +1,176 @@
1
+ # Allowances
2
+
3
+ > Create allowances and spend from another account's address balance
4
+
5
+ An [allowance](https://docs.sui.io/references/framework/sui_sui/allowance) lets a **spender** use a
6
+ **funder's** address balance, subject to spending limits. The spender signs transactions that use
7
+ it. The network must have allowance support enabled (protocol v137 or later).
8
+
9
+ ## Creating an allowance
10
+
11
+ This non-app allowance permits up to 100 USDC of spending over 24 hours. `funder` is the signer
12
+ creating the allowance. Replace `0xUsdcPackage::usdc::USDC` with your network's USDC type; amounts
13
+ use its six decimal places.
14
+
15
+ ```tsx
16
+
17
+ const USDC = '0xUsdcPackage::usdc::USDC';
18
+ const balanceType = `0x2::balance::Balance<${USDC}>`;
19
+ const expirationMs = BigInt(Date.now() + 24 * 60 * 60 * 1000);
20
+ const tx = new Transaction();
21
+
22
+ // RateLimit is a Move type, so construct its empty option with a Move call.
23
+ const noRateLimit = tx.moveCall({
24
+ target: '0x1::option::none',
25
+ typeArguments: ['0x2::allowance::RateLimit'],
26
+ });
27
+
28
+ tx.moveCall({
29
+ target: '0x2::allowance::new',
30
+ typeArguments: [balanceType],
31
+ arguments: [
32
+ tx.pure.string('USDC spending allowance'),
33
+ tx.pure.address(spenderAddress),
34
+ tx.pure.option('u256', 100_000_000n), // Lifetime cap: 100 USDC
35
+ tx.pure.option('u64', null), // No delayed start
36
+ tx.pure.option('u64', expirationMs),
37
+ noRateLimit,
38
+ ],
39
+ });
40
+
41
+ const result = await client.core.signAndExecuteTransaction({
42
+ transaction: tx,
43
+ signer: funder,
44
+ include: { effects: true },
45
+ });
46
+
47
+ if (result.$kind === 'FailedTransaction') {
48
+ throw new Error(result.FailedTransaction.status.error?.message ?? 'Allowance creation failed');
49
+ }
50
+
51
+ // This transaction creates one shared object: the allowance.
52
+ const allowance = result.Transaction.effects!.changedObjects.find(
53
+ (change) => change.idOperation === 'Created' && change.outputOwner?.$kind === 'Shared',
54
+ );
55
+ if (!allowance) throw new Error('No allowance was created');
56
+
57
+ const allowanceId = allowance.objectId;
58
+ await client.core.waitForTransaction({ digest: result.Transaction.digest });
59
+ // Give allowanceId to the spender.
60
+ ```
61
+
62
+ `allowance::new` takes `Balance<USDC>` as its type argument; the spending helpers take `USDC`.
63
+ Creation also sends the funder an `AllowanceCap`, which can revoke the allowance.
64
+
65
+ Creating an allowance does not reserve or deposit funds. The funder must have enough USDC in its
66
+ [address balance](https://docs.sui.io/onchain-finance/asset-custody/address-balances/using-address-balances#sending-funds)
67
+ when the spender withdraws.
68
+
69
+ ### Limits and expiration
70
+
71
+ An allowance requires both a lifetime cap and an expiration, unless it has a recurring rate limit.
72
+ Lifetime caps must be positive `u256` amounts. Start and expiration times use Unix milliseconds; if
73
+ both are set, the start must be earlier. Names can be at most 128 bytes.
74
+
75
+ For recurring spending, use `allowance::periodic_rate_limit(period_ms, limit)` or
76
+ `allowance::monthly_rate_limit(limit)`. Wrap the result in `0x1::option::some<RateLimit>` and pass
77
+ it as the last argument to `allowance::new`. A rate limit can replace the lifetime cap and
78
+ expiration, or apply alongside them.
79
+
80
+ ## Spending from an allowance
81
+
82
+ Pass the shared allowance ID and sign with the spender's key:
83
+
84
+ ```tsx
85
+
86
+ const USDC = '0xUsdcPackage::usdc::USDC';
87
+ const tx = new Transaction();
88
+ const balance = tx.balance({
89
+ allowance: '0xAllowanceId',
90
+ balance: 10_000_000n, // 10 USDC
91
+ type: USDC,
92
+ });
93
+
94
+ tx.moveCall({
95
+ target: '0xPackage::pool::deposit',
96
+ typeArguments: [USDC],
97
+ arguments: [tx.object('0xPoolId'), balance],
98
+ });
99
+
100
+ await client.core.signAndExecuteTransaction({ transaction: tx, signer: spender });
101
+ ```
102
+
103
+ Use `tx.coin()` instead when the next operation expects a `Coin<T>`. Both helpers default to SUI, so
104
+ pass `type: USDC` explicitly. Each amount must fit in a `u64`.
105
+
106
+ The SDK looks up the funder from the allowance ID. Spending draws only from that funder's address
107
+ balance and must satisfy the allowance's limits and expiration. The sender or a sponsor must pay gas
108
+ separately; do not combine `allowance` with `useGasCoin`.
109
+
110
+ ### Using a known funder
111
+
112
+ Pass the funder alongside the ID to skip the allowance lookup:
113
+
114
+ ```tsx
115
+
116
+ const USDC = '0xUsdcPackage::usdc::USDC';
117
+ const tx = new Transaction();
118
+ const coin = tx.coin({
119
+ allowance: { objectId: '0xAllowanceId', funder: '0xFunderAddress' },
120
+ balance: 10_000_000n, // 10 USDC
121
+ type: USDC,
122
+ });
123
+ tx.transferObjects([coin], '0xRecipientAddress');
124
+ ```
125
+
126
+ This skips the SDK's coin type and app binding checks; incorrect references fail on-chain. Building
127
+ may still need a client to resolve object versions and gas.
128
+
129
+ ## App-bound allowances
130
+
131
+ App-bound allowances require a `SpendPermit<A>` from the app as well as the spender's signature.
132
+ Pass the permit and app type to `tx.balance()` or `tx.coin()`:
133
+
134
+ ```tsx
135
+
136
+ const USDC = '0xUsdcPackage::usdc::USDC';
137
+ const tx = new Transaction();
138
+ const permit = tx.moveCall({
139
+ target: '0xAppPackage::subscriptions::authorize_payment',
140
+ arguments: [tx.object('0xSubscriptionId')],
141
+ });
142
+ const balance = tx.balance({
143
+ balance: 10_000_000n, // 10 USDC
144
+ type: USDC,
145
+ allowance: {
146
+ objectId: '0xAllowanceId',
147
+ app: { type: '0xAppPackage::subscriptions::APP', permit },
148
+ },
149
+ });
150
+ // Pass balance to the app's next operation.
151
+ ```
152
+
153
+ To create an app-bound allowance, the funder calls `allowance::propose_for_app`. The app accepts the
154
+ proposal through `allowance::issue` with a `SettingsPermit<A>`.
155
+
156
+ The authorization function and its arguments are defined by the app. The SDK handles the framework's
157
+ `app_balance_spend` call. Add `funder` to the allowance reference to skip the metadata lookup.
158
+
159
+ A permit authorizes one spend but does not bind its amount or recipient. Apps that need to enforce
160
+ those must redeem the withdrawal inside their own Move function, using `tx.withdrawal()` as the
161
+ input.
162
+
163
+ ```tsx
164
+
165
+ const tx = new Transaction();
166
+ const withdrawal = tx.withdrawal({
167
+ amount: 10_000_000n,
168
+ type: '0xUsdcPackage::usdc::USDC',
169
+ from: 'allowance',
170
+ allowance: '0xAllowanceId',
171
+ funder: '0xFunderAddress',
172
+ });
173
+ // Pass withdrawal to the app's Move function that redeems it.
174
+ ```
175
+
176
+ `from: 'allowance'` requires both `allowance` and `funder`; this helper does not look them up.
@@ -20,7 +20,8 @@ invalidated by other transactions from the same address executing concurrently.
20
20
  ## `tx.coin` and `tx.balance`
21
21
 
22
22
  `tx.coin()` and `tx.balance()` are the recommended ways to get tokens in a transaction. They
23
- automatically draw from both coin objects and address balances.
23
+ automatically draw from both coin objects and address balances. To spend funds authorized by another
24
+ account, see [Allowances](./allowances.mdx).
24
25
 
25
26
  ### Getting a `Coin`
26
27
 
@@ -74,11 +75,11 @@ tx.moveCall({
74
75
 
75
76
  ### Options
76
77
 
77
- | Option | Type | Default | Description |
78
- | ------------ | ------------------ | ---------- | ------------------------------------------------------------------------ |
79
- | `balance` | `bigint \| number` | _required_ | Amount in base units (MIST for SUI) |
80
- | `type` | `string` | SUI | Coin type. Defaults to `0x2::sui::SUI` |
81
- | `useGasCoin` | `boolean` | `true` | For SUI, split from the gas coin. Set `false` for sponsored transactions |
78
+ | Option | Type | Default | Description |
79
+ | ------------ | ---------------------------- | ---------- | --------------------------------------------------------------------------------------- |
80
+ | `balance` | `bigint \| number \| string` | _required_ | Amount in base units (MIST for SUI); use safe integer numbers or bigint/decimal strings |
81
+ | `type` | `string` | SUI | Coin type T, not Balance&lt;T&gt;. Defaults to `0x2::sui::SUI` |
82
+ | `useGasCoin` | `boolean` | `true` | For SUI, allow splitting the gas coin. Set `false` for sponsored transactions |
82
83
 
83
84
  For SUI, `tx.coin()` splits from the gas coin by default. For sponsored transactions where the gas
84
85
  coin belongs to the sponsor, set `useGasCoin: false`:
@@ -89,7 +90,7 @@ tx.transferObjects([tx.coin({ balance: 100n, useGasCoin: false })], recipient);
89
90
 
90
91
  ### `coinWithBalance`
91
92
 
92
- `coinWithBalance()` is a standalone alias for `tx.coin()`:
93
+ `coinWithBalance()` is a standalone helper for sender-funded coins:
93
94
 
94
95
  ```tsx
95
96
 
@@ -100,7 +101,8 @@ tx.transferObjects([coinWithBalance({ balance: 1_000_000_000 })], recipient);
100
101
  ## How resolution works
101
102
 
102
103
  When you call `tx.coin()` or `tx.balance()`, the SDK adds a placeholder intent to the transaction.
103
- At build time, the resolver replaces it with concrete commands based on the sender's funds:
104
+ For sender-funded requests, the resolver replaces it at build time with concrete commands based on
105
+ the sender's funds:
104
106
 
105
107
  - **`tx.balance()` with sufficient address balance:** Uses a direct `FundsWithdrawal` through
106
108
  `balance::redeem_funds`. No coin objects are used, so the transaction has no versioned object
@@ -115,7 +117,8 @@ At build time, the resolver replaces it with concrete commands based on the send
115
117
  The resolver prefers address balances when possible to avoid introducing versioned object
116
118
  dependencies.
117
119
 
118
- Zero-balance requests resolve to `balance::zero` or `coin::zero` with no network lookups.
120
+ Sender-funded zero-balance requests resolve to `balance::zero` or `coin::zero` with no network
121
+ lookups.
119
122
 
120
123
  ## Checking balances
121
124
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "author": "Mysten Labs <build@mystenlabs.com>",
4
4
  "description": "Sui TypeScript API",
5
5
  "homepage": "https://sdk.mystenlabs.com",
6
- "version": "2.30.0",
6
+ "version": "2.31.0",
7
7
  "license": "Apache-2.0",
8
8
  "sideEffects": false,
9
9
  "files": [
package/src/bcs/bcs.ts CHANGED
@@ -96,6 +96,10 @@ export const WithdrawalType = bcs.enum('WithdrawalType', {
96
96
  export const WithdrawFrom = bcs.enum('WithdrawFrom', {
97
97
  Sender: null,
98
98
  Sponsor: null,
99
+ SenderAllowance: bcs.struct('SenderAllowance', {
100
+ funder: Address,
101
+ allowance: Address,
102
+ }),
99
103
  });
100
104
 
101
105
  // Rust: crates/sui-types/src/transaction.rs
package/src/bcs/types.ts CHANGED
@@ -44,7 +44,8 @@ export function isPureArg(arg: any): arg is PureArg {
44
44
 
45
45
  type Reservation = { MaxAmountU64: number | string };
46
46
  type WithdrawalTypeArg = { Balance: TypeTag };
47
- type WithdrawFrom = { Sender: null } | { Sponsor: null };
47
+ type WithdrawFrom =
48
+ { Sender: null } | { Sponsor: null } | { SenderAllowance: { funder: string; allowance: string } };
48
49
  type FundsWithdrawalArg = {
49
50
  reservation: Reservation;
50
51
  typeArg: WithdrawalTypeArg;
@@ -66,10 +66,12 @@ export async function coreClientResolveTransactionPlugin(
66
66
  for (const input of transactionData.inputs) {
67
67
  if (input.$kind !== 'FundsWithdrawal' || !normalizedGasPayer) continue;
68
68
  if (normalizeStructTag(input.FundsWithdrawal.typeArg.Balance) !== SUI_TYPE_ARG) continue;
69
-
70
- const withdrawalOwner = input.FundsWithdrawal.withdrawFrom.Sender
71
- ? transactionData.sender
72
- : gasPayer;
69
+ const source = input.FundsWithdrawal.withdrawFrom;
70
+ const withdrawalOwner = source.SenderAllowance
71
+ ? source.SenderAllowance.funder
72
+ : source.Sender
73
+ ? transactionData.sender
74
+ : gasPayer;
73
75
  if (
74
76
  withdrawalOwner &&
75
77
  normalizeSuiAddress(withdrawalOwner) === normalizedGasPayer &&
@@ -20,7 +20,7 @@ import {
20
20
  TransactionExpiration_TransactionExpirationKind,
21
21
  } from '../grpc/proto/sui/rpc/v2/transaction.js';
22
22
  import type { ObjectReference } from '../grpc/proto/sui/rpc/v2/object_reference.js';
23
- import type { Input } from '../grpc/proto/sui/rpc/v2/input.js';
23
+ import type { FundsWithdrawal, Input } from '../grpc/proto/sui/rpc/v2/input.js';
24
24
  import { FundsWithdrawal_Source, Input_InputKind } from '../grpc/proto/sui/rpc/v2/input.js';
25
25
  import type { Command } from '../grpc/proto/sui/rpc/v2/transaction.js';
26
26
  import type { Argument } from '../grpc/proto/sui/rpc/v2/argument.js';
@@ -102,10 +102,7 @@ function callArgToGrpcInput(arg: CallArg): Input {
102
102
  ? BigInt(withdrawal.reservation.MaxAmountU64)
103
103
  : undefined,
104
104
  coinType: withdrawal.typeArg.$kind === 'Balance' ? withdrawal.typeArg.Balance : undefined,
105
- source:
106
- withdrawal.withdrawFrom.$kind === 'Sponsor'
107
- ? FundsWithdrawal_Source.SPONSOR
108
- : FundsWithdrawal_Source.SENDER,
105
+ ...tsWithdrawFromToGrpc(withdrawal.withdrawFrom),
109
106
  },
110
107
  };
111
108
  }
@@ -115,6 +112,46 @@ function callArgToGrpcInput(arg: CallArg): Input {
115
112
  }
116
113
  }
117
114
 
115
+ function tsWithdrawFromToGrpc(
116
+ withdrawFrom: Extract<CallArg, { FundsWithdrawal: unknown }>['FundsWithdrawal']['withdrawFrom'],
117
+ ): Pick<FundsWithdrawal, 'source' | 'funder' | 'allowance'> {
118
+ switch (withdrawFrom.$kind) {
119
+ case 'Sender':
120
+ return { source: FundsWithdrawal_Source.SENDER };
121
+ case 'Sponsor':
122
+ return { source: FundsWithdrawal_Source.SPONSOR };
123
+ case 'SenderAllowance':
124
+ return {
125
+ source: FundsWithdrawal_Source.SENDER_ALLOWANCE,
126
+ funder: withdrawFrom.SenderAllowance.funder,
127
+ allowance: withdrawFrom.SenderAllowance.allowance,
128
+ };
129
+ default:
130
+ throw new Error(`Unknown WithdrawFrom kind: ${JSON.stringify(withdrawFrom)}`);
131
+ }
132
+ }
133
+
134
+ function grpcWithdrawFromToTs(
135
+ withdrawal: FundsWithdrawal | undefined,
136
+ ): Extract<CallArg, { FundsWithdrawal: unknown }>['FundsWithdrawal']['withdrawFrom'] {
137
+ switch (withdrawal?.source) {
138
+ case FundsWithdrawal_Source.SPONSOR:
139
+ return { $kind: 'Sponsor', Sponsor: true };
140
+ case FundsWithdrawal_Source.SENDER_ALLOWANCE:
141
+ if (!withdrawal.funder || !withdrawal.allowance) {
142
+ throw new Error(
143
+ `SENDER_ALLOWANCE withdrawal is missing funder or allowance: ${JSON.stringify(withdrawal)}`,
144
+ );
145
+ }
146
+ return {
147
+ $kind: 'SenderAllowance',
148
+ SenderAllowance: { funder: withdrawal.funder, allowance: withdrawal.allowance },
149
+ };
150
+ default:
151
+ return { $kind: 'Sender', Sender: true };
152
+ }
153
+ }
154
+
118
155
  /**
119
156
  * Converts a TypeScript Argument to gRPC Argument
120
157
  */
@@ -429,10 +466,7 @@ function grpcInputToCallArg(input: Input): CallArg {
429
466
  $kind: 'Balance' as const,
430
467
  Balance: input.fundsWithdrawal?.coinType ?? '0x2::sui::SUI',
431
468
  },
432
- withdrawFrom:
433
- input.fundsWithdrawal?.source === FundsWithdrawal_Source.SPONSOR
434
- ? { $kind: 'Sponsor' as const, Sponsor: true as const }
435
- : { $kind: 'Sender' as const, Sender: true as const },
469
+ withdrawFrom: grpcWithdrawFromToTs(input.fundsWithdrawal),
436
470
  },
437
471
  };
438
472