csrfField() error

When I try to use csrf protection I get an error.

I have added {{ csrfField() }} to my form

I get following error

Cannot call function csrfField from user/payments/pay/unpaidHours.edge view

 * @return {Mixed}
   */
  callFn (name, args) {
    const fn = this.resolve(name)
    if (typeof (fn) !== 'function') {
      throw new Error(`Cannot call function ${name} from ${this.$viewName} view`)
    }
    return fn.apply(this, args)
  }

  /**

Here is my controller that renders the view

 async index({ request, response, view, auth }) {
    var user = await auth.getUser()
    var paidInvoices = await Invoice
      .query()
      .where('user_id', user.id)
      .has('payment')
      .with('payment')
      .withCount('invoiceLines')
      .fetch()
    var unpaidInvoices =
      await Invoice
        .query()
        .where('user_id', user.id)
        .doesntHave('payment')
        .withCount('invoiceLines')
        .fetch()

    var unpaidHours = await Flyinghours
      .query()
      .where('user_id', user.id)
      .doesntHave('invoiceLine.invoice.payment')
      .orderBy('flight_start')
      .fetch()

    return view.render('user.payments.index', { unpaidHours: unpaidHours.toJSON(), unpaidInvoices: unpaidInvoices.toJSON(), paidInvoices: paidInvoices.toJSON() })

and here is my view

<div class="p-3 border-2 border-blue-light rounded shadow overflow-x-scroll">
  <div>

    <div class="text-lg text-blue font-semibold mb-3">Unpaid hours <span class="text-sm text-blue-light">Payment Terms {{envGet('invoice_payment_terms')}} days</span></div>
    <div class="flex mb-2 pb-2 border-b-2 border-blue-lighter">
      <div class="w-1/5 font-semibold">Select</div>
      <div class="w-1/5 font-semibold">Flight Date</div>
      <div class="w-1/5 font-semibold">Engine Time</div>
      <div class="w-1/5 font-semibold">Price</div>
      <div class="w-1/5 font-semibold">Due Days</div>
    </div>
  
    <form action="/user/invoices/addhours" method="POST">
      {{ csrfField() }}
    @each(log in unpaidHours)
    <div class="text-sm lg:text-base flex p-2 border-b-2 border-grey-lighter {{invoiceDays(log.flight_start)<=0?'bg-red-light rounded text-white':''}}">
        <div class="w-1/5"><input type="checkbox" name="logs[{{log.id}}]"></div>
        <div class="w-1/5">{{moment(log.flight_start).format("YYYY-MM-DD")}}</div>
        <div class="w-1/5">{{hoursAndMinutes(log.engine_minutes)}} @ £{{log.cost_per_hour.toFixed(2)}} ph</div>
        <div class="w-1/5">£{{flyingHourPrice(log.engine_minutes, log.cost_per_hour)}}</div>
        <div class="w-1/5 text-sm">{{paymentDueDate(log.flight_start)}} ({{invoiceDays(log.flight_start)}} days)</div>
      </div>
    @else
    <div class="text-green p-3 font-semibold">Hurray, you have no unpaid hours!</div>
    @endeach
    @if(unpaidHours[0].id)
    <div>
      <button type="submit" class="mt-3 border-2 border-blue-dark bg-blue hover:bg-blue-light p-1 text-white rounded shadow" title="Create invoice from selected log hours">Create Invoice</button>
    </div>
    @endif
    
    </form>
  </div>
</div>

I have installed shield

Here is my kernal file

'use strict'

/** @type {import('@adonisjs/framework/src/Server')} */
const Server = use('Server')

/*
|--------------------------------------------------------------------------
| Global Middleware
|--------------------------------------------------------------------------
|
| Global middleware are executed on each http request only when the routes
| match.
|
*/
const globalMiddleware = [
  'Adonis/Middleware/BodyParser',
  'Adonis/Middleware/Session',
  'Adonis/Middleware/Shield',
  'Adonis/Middleware/AuthInit',
  'App/Middleware/ConvertEmptyStringsToNull',
]

/*
|--------------------------------------------------------------------------
| Named Middleware
|--------------------------------------------------------------------------
|
| Named middleware is key/value object to conditionally add middleware on
| specific routes or group of routes.
|
| // define
| {
|   auth: 'Adonis/Middleware/Auth'
| }
|
| // use
| Route.get().middleware('auth')
|
*/
const namedMiddleware = {
  auth: 'Adonis/Middleware/Auth',
  guest: 'Adonis/Middleware/AllowGuestOnly'
}

/*
|--------------------------------------------------------------------------
| Server Middleware
|--------------------------------------------------------------------------
|
| Server level middleware are executed even when route for a given URL is
| not registered. Features like `static assets` and `cors` needs better
| control over request lifecycle.
|
*/
const serverMiddleware = [
  'Adonis/Middleware/Static',
  'Adonis/Middleware/Cors'
]

Server
  .registerGlobal(globalMiddleware)
  .registerNamed(namedMiddleware)
  .use(serverMiddleware)

Here is my config file

'use strict'

module.exports = {
  /*
  |--------------------------------------------------------------------------
  | Content Security Policy
  |--------------------------------------------------------------------------
  |
  | Content security policy filters out the origins not allowed to execute
  | and load resources like scripts, styles and fonts. There are wide
  | variety of options to choose from.
  */
  csp: {
    /*
    |--------------------------------------------------------------------------
    | Directives
    |--------------------------------------------------------------------------
    |
    | All directives are defined in camelCase and here is the list of
    | available directives and their possible values.
    |
    | https://content-security-policy.com
    |
    | @example
    | directives: {
    |   defaultSrc: ['self', '@nonce', 'cdnjs.cloudflare.com']
    | }
    |
    */
    directives: {
    },
    /*
    |--------------------------------------------------------------------------
    | Report only
    |--------------------------------------------------------------------------
    |
    | Setting `reportOnly=true` will not block the scripts from running and
    | instead report them to a URL.
    |
    */
    reportOnly: false,
    /*
    |--------------------------------------------------------------------------
    | Set all headers
    |--------------------------------------------------------------------------
    |
    | Headers staring with `X` have been depreciated, since all major browsers
    | supports the standard CSP header. So its better to disable deperciated
    | headers, unless you want them to be set.
    |
    */
    setAllHeaders: false,

    /*
    |--------------------------------------------------------------------------
    | Disable on android
    |--------------------------------------------------------------------------
    |
    | Certain versions of android are buggy with CSP policy. So you can set
    | this value to true, to disable it for Android versions with buggy
    | behavior.
    |
    | Here is an issue reported on a different package, but helpful to read
    | if you want to know the behavior. https://github.com/helmetjs/helmet/pull/82
    |
    */
    disableAndroid: true
  },

  /*
  |--------------------------------------------------------------------------
  | X-XSS-Protection
  |--------------------------------------------------------------------------
  |
  | X-XSS Protection saves applications from XSS attacks. It is adopted
  | by IE and later followed by some other browsers.
  |
  | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
  |
  */
  xss: {
    enabled: true,
    enableOnOldIE: false
  },

  /*
  |--------------------------------------------------------------------------
  | Iframe Options
  |--------------------------------------------------------------------------
  |
  | xframe defines whether or not your website can be embedded inside an
  | iframe. Choose from one of the following options.
  | @available options
  | DENY, SAMEORIGIN, ALLOW-FROM http://example.com
  |
  | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
  */
  xframe: 'DENY',

  /*
  |--------------------------------------------------------------------------
  | No Sniff
  |--------------------------------------------------------------------------
  |
  | Browsers have a habit of sniffing content-type of a response. Which means
  | files with .txt extension containing Javascript code will be executed as
  | Javascript. You can disable this behavior by setting nosniff to false.
  |
  | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
  |
  */
  nosniff: true,

  /*
  |--------------------------------------------------------------------------
  | No Open
  |--------------------------------------------------------------------------
  |
  | IE users can execute webpages in the context of your website, which is
  | a serious security risk. Below option will manage this for you.
  |
  */
  noopen: true,

  /*
  |--------------------------------------------------------------------------
  | CSRF Protection
  |--------------------------------------------------------------------------
  |
  | CSRF Protection adds another layer of security by making sure, actionable
  | routes does have a valid token to execute an action.
  |
  */
  csrf: {
    enable: true,
    methods: ['POST', 'PUT', 'DELETE'],
    filterUris: [],
    cookieOptions: {
      httpOnly: false,
      sameSite: true,
      path: '/',
      maxAge: 7200
    }
  }
}

I solved the issue. I was trying to use {{ csrfField() }} in a component, but it looks like that function is only available directly from the edge file that is called by the controller, so I just passed the value into my component like so.

@!component('user.payments.pay.unpaidHours', unpaidHours=unpaidHours, csrf=csrfField())

Then in my component, I used the passed in value.

<form>
...
{{csrf}}
...
</form>