defendAsyncMethod = (
  getContext,
  behaviorMethod,
  methodGuardPayload,
  label,
) => {
  const { returnGuard } = methodGuardPayload;
  const isRawReturn = isRawGuard(returnGuard);

  const { awaitIndexes, rawMethodGuardPayload } = desync(methodGuardPayload);
  const matchConfig = buildMatchConfig(rawMethodGuardPayload);

  const { asyncMethod } = {
    // Note purposeful use of `this` and concise method syntax
    asyncMethod(...args) {
      const awaitList = [];
      for (const i of awaitIndexes) {
        if (i >= args.length) {
          break;
        }
        awaitList.push(args[i]);
      }
      const p = Promise.all(awaitList);
      const syncArgs = [...args];
      const resultP = E.when(
        p,
        /** @param {any[]} awaitedArgs */ awaitedArgs => {
          for (let j = 0; j < awaitedArgs.length; j += 1) {
            syncArgs[awaitIndexes[j]] = awaitedArgs[j];
          }
          // Get the context after all waiting in case we ever do revocation
          // by removing the context entry. Avoid TOCTTOU!
          const context = getContext(this);
          const realArgs = defendSyncArgs(syncArgs, matchConfig, label);
          return apply(behaviorMethod, context, realArgs);
        },
      );
      return E.when(resultP, fulfillment => {
        if (!isRawReturn) {
          mustMatch(harden(fulfillment), returnGuard, `${label}: result`);
        }
        return fulfillment;
      }).catch(reason =>
        // Done is a chained `.catch` rather than an onRejected clause of the
        // `E.when` above in case the `mustMatch` throws.
        Promise.reject(toThrowable(reason)),
      );
    },
  };
  return asyncMethod;
}
@param {(representative: any) => ClassContext | KitContext} getContext
@param {CallableFunction} behaviorMethod
@param {MethodGuardPayload} methodGuardPayload
@param {string} label