Automate Signing Transactions

Part of the Docker setup in order to automate signing transactions (approvals/rejections)

Sign On Transactions (Automatic Flow)

On a transaction creation in Inabit, Inabit will send a request to the Approver to handle the requested transaction approval, and sign on the approve/reject decision.

In order to handle transaction approvals:

  1. Approver (API Signer) needs to be in Paired status.

  2. Configure an external validation url ('endpoint'), implementing the Approver's required approval logics:

    • The external validation endpoint is expected to expose a 'post' http endpoint for validation purpose.

**connectivity to the endpoint must be enabled.

           
      VALIDATION_CALLBACK_URL=http://koko.com/validation
      
  • The endpoint will automatically be passed a TransactionValidationData json object at the body of the http 'post' call. with the following structure:

 
  {
        createTime: string;
        transactionId: string;
        transactionType: string;   // Withdrawal / Deposit / Swap
        initiatorId: string;
        organizationId: string;
        network: string;
        walletId: string;
        walletAddress: string;
        to: string;
        coin: string;
        amount: number;
        baseCurrencyCode: string;
        baseCurrencyAmount: number;
  };
  
  • The endpoint is expected to return a response with the following structure:

{ approved: boolean }  // allowed: { approved: true / false }
  • In case of an exception a retry will be scheduled to execute in 3 minutes time, up to 10 times (10 * 3 minutes).

  VALIDATION_RETRY_INTERVAL_MINUTES=3
  VALIDATION_RETRY_MAX_COUNT=10
  • On receiving a validation url call response, a signed approval (using Approver's key) will be sent back automatically to Inabit, for further processing (policy enforcement).

Mock Validation

It is also possible to mock external validation url using a predefined endpoint (transaction/validate) on the Approver, and control the required outcome. Using the following configuration

VALIDATION_CALLBACK_URL=[APPROVER_URL]transaction/validate   # replace [APPROVER_URL] with the Approver's url. 
VALIDATION_MOCK_SET_RESULT=rejected   # allowed: approved / rejected / exception

Initiation trace log example:

{
  level: 'info',
  message: 'Init Approver started',
  metadata: { timestamp: '2024-02-21T08:54:11.990Z' },
  timestamp: '2024-02-21T08:54:11.990Z'
}
{
  level: 'info',
  message: 'Checking if Approver is paired already.',
  metadata: { timestamp: '2024-02-21T08:54:15.174Z' },
  timestamp: '2024-02-21T08:54:15.174Z'
}
{
  level: 'info',
  message: 'Approver needs to be paired, starts a pairing process...',
  metadata: { timestamp: '2024-02-21T08:54:16.071Z' },
  timestamp: '2024-02-21T08:54:16.071Z'
}
{
  level: 'info',
  message: 'Getting a pairing token.',
  metadata: { timestamp: '2024-02-21T08:54:16.075Z' },
  timestamp: '2024-02-21T08:54:16.075Z'
}
{
  level: 'info',
  message: 'Getting a pairing code',
  metadata: { timestamp: '2024-02-21T08:54:17.555Z' },
  timestamp: '2024-02-21T08:54:17.555Z'
}
{
  level: 'info',
  message: 'Pairing code: c754ce6d209dcc1b6f2312903ef31f0ac297b63e5dead29a6b877ecad8c77ada',
  metadata: { timestamp: '2024-02-21T08:54:17.560Z' },
  timestamp: '2024-02-21T08:54:17.560Z'
}
{
  level: 'info',
  message: 'Getting a signature key',
  metadata: { timestamp: '2024-02-21T08:54:17.562Z' },
  timestamp: '2024-02-21T08:54:17.562Z'
}
{
  level: 'info',
  message: 'signature key : eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImp3ayI6eyJrdHkiOiJFQyIsIngiOiItWGJ6Qjdfa2I2cXNJdDRxTTg3cU5OMC1TeTVZWU9NbmN1R1F4U1E1YmZVIiwieSI6IjR6Qk9zR1Yza0NTek4zSW02cE1KSjZzcUJYVW03RHBfRjJmbWNhbEhGVzgiLCJjcnYiOiJQLTI1NiIsImtpZCI6Im01QXpWcWJjQURRK25hSmh5Y1E4b0JXTFJYYTBqeDVOQjEyeW1KQklyYlU9In19.eyJ2ZXJpZnlfa2V5Ijp7Imp3ayI6eyJrdHkiOiJFQyIsIngiOiItWGJ6Qjdfa2I2cXNJdDRxTTg3cU5OMC1TeTVZWU9NbmN1R1F4U1E1YmZVIiwieSI6IjR6Qk9zR1Yza0NTek4zSW02cE1KSjZzcUJYVW03RHBfRjJmbWNhbEhGVzgiLCJjcnYiOiJQLTI1NiIsImtpZCI6Im01QXpWcWJjQURRK25hSmh5Y1E4b0JXTFJYYTBqeDVOQjEyeW1KQklyYlU9In19LCJtZXNzYWdlIjoie1wiY3JlYXRvclwiOntcImVtYWlsXCI6XCJpc3N1ZXJAZXhhbXBsZS5jb21cIixcIm9yZ2FuaXphdGlvbk5hbWVcIjpcIm15LW9yZ2FuaXphdGlvblwifX0iLCJtYWMiOiJhOGJiMjA3ZGRiMTk2MmE1YTg3MjY2YTkzYWI4MDlmOTY1MDcwN2U0NmNkOTE3M2FiYjZhOTE4MDYwY2Q3ODU2IiwiaWF0IjoxNzA4NTA1NjU3fQ.1ZBl8XRllNyoJNWNPaB6iAu9VbQh2Jcr0hXRPppD8wES1Z5ZckPXTe0eqBmmTtZS_l4Gtip7kwOfFMi-jNtbIN',
  metadata: { timestamp: '2024-02-21T08:54:17.578Z' },
  timestamp: '2024-02-21T08:54:17.578Z'
}
{
  level: 'info',
  message: 'Sending pairing data',
  metadata: { timestamp: '2024-02-21T08:54:17.581Z' },
  timestamp: '2024-02-21T08:54:17.581Z'
}
{
  level: 'info',
  message: 'Approver is waiting for approval',
  metadata: { timestamp: '2024-02-21T08:54:20.767Z' },
  timestamp: '2024-02-21T08:54:20.767Z'
}
{
  level: 'info',
  message: 'Init Approver completed, waiting for pairing process completion.',
  metadata: { timestamp: '2024-02-21T08:54:20.769Z' },
  timestamp: '2024-02-21T08:54:20.769Z'
}
[Nest] 4308  - 02/21/2024, 8:54:20 AM     LOG [NestApplication] Nest application successfully started +8819ms
{
  level: 'info',
  message: 'Refresh token completed',
  metadata: { timestamp: '2024-02-21T08:54:20.803Z' },
  timestamp: '2024-02-21T08:54:20.803Z'
}
{
  level: 'info',
  message: 'Scheduling next refresh token in 15 days',
  metadata: { timestamp: '2024-02-21T08:54:20.806Z' },
  timestamp: '2024-02-21T08:54:20.806Z'
}