[![Integration Tests](https://github.com/BitEscrow/escrow-core/actions/workflows/integration.yml/badge.svg?branch=master)](https://github.com/BitEscrow/escrow-core/actions/workflows/integration.yml)

# escrow-core

A light-weight, non-custodial protocol for using Bitcoin in a `covenant-based` smart contract.

Features:
  * Method libraries for every part of the protocol.
  * Multi-platform client with minimal dependencies.
  * Run-time schema validation (using zod).
  * E2E test suite for regtest, signet, and testnet.

Comimg Soon:
  * Return receipts on witness submission.
  * Improved code comments and documentation.
  * new `templates` field for raw tx templates.
  * `hashlock` and `oracle` programs for vm.
  * OpenAPI spec document.

## How It Works

The protocol involves three parties:

**Members** : The participating members of the contract.
**Funders** : Those depositing funds into the contract (may be members).
**Agent**   : The server hosting the escrow contract (BitEscrow API).

The protocol is split into three phases: `negotiation`, `funding`, and `settlement`. Each phase represents a round of communication in the protocol.

### Negotiation

The `members` of the contract must first negotiate and agree on a `proposal` document. This is a human-readable document which contains all of the terms of the contract. It is written and consumed in JSON format, and designed for collaboration (much like a PSBT).

```ts
{
  title    : 'Basic two-party contract with third-party dispute resolution.',
  content  : '{}',
  expires  : 14400,
  network  : 'regtest',
  paths: [
    [ 'payout', 90000, 'bcrt1qhlm6uva0q2m5dq4kjd9uzsankkxe9pza5uylcs' ],
    [ 'return', 90000, 'bcrt1qemwtdfh9uncvw7jlq4ux7p7stl9lgvfxa8t05g' ]
  ],
  payments : [[ 10000, 'bcrt1qxemag7t72rlrhl2ezsnsprmunmnzc35nmaph6v' ]],
  programs : [
    [ 'endorse', 'dispute', 'payout', 1, '9997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be' ],
    [ 'endorse', 'resolve',      '*', 1, '9094567ba7245794198952f68e5723ac5866ad2f67dd97223db40e14c15b092e' ],
    [ 'endorse', 'close|resolve','*', 2, 
      '9997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be',
      '4edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10'
    ]
  ],
  schedule : [[ 7200, 'close', 'payout|return' ]],
  value    : 100000,
  version  : 1
}
```

If desired, a service `provider` can offer a platform for negotiating the proposal. The protocol is designed for third-parties to help with coordination, and offer their own services such as arbitration.

There is no specification placed on how to communicate a proposal between parties. There are already many great communication protocols that exist in the wild, and they all support JSON. Feel free to use your favorite one!

> Note: The `agent` does not arbitrate disputes or take part in negotiations. This is strictly by design. While BitEscrow may offer these services, the protocol is designed so that members and third-parties can negotiate freely, without the agent being involved.

### Funding

Once a proposal is finalized, it is delivered to the `agent` server, who hosts the contract, and coordinates with `funders`.

Each funder negotiaties a `deposit` with the agent using a 2-of-2 multi-signature address with a time-locked refund path.

```ts
// Account goes here
```

The funder then delivers a batch of pre-signed transactions which authorizes each of the spending paths of the contract.

Once the pre-signed `covenant` is made, the funds are locked in escrow. Once all deposits have bee locked and confirmed, the contract becomes active.

### Settlement

The final round of the escrow process is the `settlement`. This is the most fun part of the protocol, as members of the contract get to debate about how the money shall be spent.



At this phase:

  * The agent is bound by the covenant, and can only settle the contract using a pre-authorized spending path.
  * The agent does have control over that selection process, and can implement any protocol.

To maximize the power of the first point, and minimize risk from the second point, both the `members` and `agent` interact with the contract through the use of a virtual machine. The consensus of this machine is governed by the terms of the proposal, which define:

  - The `paths` available to spend in the contract.
  - The `actions` that can be taken on a given path.
  - The `method` used to trigger those actions.
  - The `params` used to configure each method.

> Note: Each method involves the creation / validation of a cryptography proof.

The sum of these definitions constitutes a `program` that can be executed.

To execute a program, a `member` submits their arguments to the `agent`, who then uses the machine to evaluate the arguments. If the arguments are valid, then the machine state is updated. The agent then creates a basic commit hash that records the changes that took place. This hash is signed and returned to the `member` as a form of receipt.

> Note: Each commit proof links to the previous, forming a git-style hash chain of attribution.

Once the machine has computed a result for the contract, the agent then proceeds to complete each covenant and broadcast the selected path via an on-chain transaction.

**Agents**  

A quick note about agents. From the protocol perspective, agents are meant to be like meeseeks: their purpose in the life of a contract is to collect signatures, crunch numbers, then spit out a transaction for a nominal fee. Any descision outside of a 0 or 1 equals pain for the agent.

The proposal is designed to outline a simple decision tree for the agent to follow, so that all decisions are verifiable. The agent is not designed to be an arbitrator, rather the arbitrator (if included) would be a member of the contract, and would interact with the agent under the same terms.

At a high level, we are combining the use of pre-signed covenants, with a protocol for establishing an end-to-end cryptographic contract between the three parties. The contract guarantees that the agent can't cheat without being caught, and the covenant guarantees the agent has no direct control over the funds.

Thankfully, all of this can done by open-source computer software. :-)

## Protocol Flow

> **Scenario**: Sales agreement between a buyer (alice) and seller (bob) with third-party (carol) arbitration.

Step 0 (draft proposal):  
  * Alice prepares a proposal with Bob. They both agree on Carol to resolve disputes.

Step 1 (create contract):  
  * Bob submits his proposal to the agent and receives a contract.
  * Bob shares this contract with Alice.

Step 2 (deposit & covenant):  
  * Alice deposits her funds into a 2-of 2 account with the contract agent.
  * Alice signs a covenant that spends her funds to either 'payout' or 'refund' path.
  * Once the deposit is confirmed on-chain, the contract becomes active.
  
Step 3a (settle contract - happy path):  
  * Alice receives her widget and forgets about Bob.
  * The contract schedule closes automatically on 'payout'.
  * Bob gets the funds, Alice can verify the CVM execution.

Step 3b (settle contract - so-so path):  
  * Alice doesn't like her widget.
  * Alice and Bob both agree to sign the 'refund' path.
  * Alice gets a partial refund, Bob still keeps his fees.

Step 3c (dispute contract - unhappy path):  
  * Alice claims she didn't get a widget, and disputes the payout.
  * Carol now has authority to settle the contract.
  * Carol decides on the 'refund' path.
  * Alice gets a partial refund, Bob still keeps his fees.

Step 3d (expired contract - ugly path):  
  * Alice claims she didn't get a widget, and disputes the payout.
  * Carol is on a two-week cruise in the bahamas.
  * The proposal did not include any auto-settlement terms.
  * The contract hangs in dispute until it expires.
  * The fallback path is executed, or if not defined, all deposits are refunded.

Step 3e (expired deposits - horrific path):  
  * Everything in 3d happens, except the last bit.
  * The entire escrow platform goes down in flames.
  * All deposits expire, and can be swept using the refund path.

## The Proposal

A proposal is the precursor to creating a contract. It defines the terms of the contract and how the CVM should be initialized. It is written in a simple JSON format that is easy to read, for humans and machines alike.

```ts
{
  title    : 'Basic two-party contract with third-party dispute resolution.',
  details  : 'n/a',
  expires  : 14400,
  network  : 'regtest',
  paths: [
    [ 'payout', 90000, 'bcrt1qhlm6uva0q2m5dq4kjd9uzsankkxe9pza5uylcs' ],
    [ 'return', 90000, 'bcrt1qemwtdfh9uncvw7jlq4ux7p7stl9lgvfxa8t05g' ]
  ],
  payments : [[ 10000, 'bcrt1qxemag7t72rlrhl2ezsnsprmunmnzc35nmaph6v' ]],
  programs : [
    [ 'endorse', 'dispute', 'payout', 1, '9997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be' ],
    [ 'endorse', 'resolve',      '*', 1, '9094567ba7245794198952f68e5723ac5866ad2f67dd97223db40e14c15b092e' ],
    [ 'endorse', 'close|resolve','*', 2, 
      '9997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be',
      '4edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10'
    ]
  ],
  schedule : [[ 7200, 'close', 'payout|return' ]],
  value    : 100000,
  version  : 1
}
```

The format is designed to be collaborative and shared between parties. Each member can add their own terms to the `paths`, `payments`, `programs`, and `schedule` fields. All other fields are require a unanimous consensus across members.

## The Contract

The contract serves as the main document between depositors and members. It provides information for making deposits, constructing a covenant, and hosting the CVM for members to interact with.

```ts
interface ContractData {
  activated   : null | number
  agent_id    : string
  agent_key   : string
  agent_pn    : string
  balance     : number
  cid         : string
  deadline    : number
  expires_at  : null | number
  fees        : Payment[]
  moderator   : string | null
  outputs     : SpendTemplate[]
  pending     : number
  prop_id     : string
  published   : number
  settled     : boolean
  settled_at  : number | null
  spent       : boolean,
  spent_at    : number | null
  spent_txid  : string | null
  status      : ContractStatus
  terms       : ProposalData
  total       : number
  updated_at  : number
  vm_state    : null | ContractState
}
```

```ts
// The different states of a Contract.
export type ContractStatus = 
  'published' | // Initial state of a contract. Can be cancelled. 
  'funded'    | // Contract is funded, not all deposits are confirmed.
  'secured'   | // All deposits are confirmed, awaiting delayed execution. 
  'pending'   | // Contract is ready for activation
  'active'    | // Contract is active, CVM running, clock is ticking.
  'closed'    | // Contract is closed, ready for settlement.
  'spent'     | // Contract is spent, tx in mempool.
  'settled'   | // Contract is settled, tx is confirmed.
  'canceled'  | // Contract canceled or expired during funding.
  'expired'   | // Contract expired during execution.
  'error'       // Something broke, may need manual intervention.
```

Once funds are secured and the contract is active, the CVM is initialized and ready to accept arguments.

```ts
// The state of a newly born CVM, fresh from the womb.
state: {
  commits  : [],
  head     : 'df015d478a970033af061c7ed0152b97907c148b51353a8a33f79cf0b3d87350',
  paths    : [ [ 'payout', 0 ], [ 'return', 0 ] ],
  programs : [],
  result   : null,
  start    : 1696362768,
  status   : 'init',
  steps    : 0,
  store    : [],
  updated  : 1696362768
}
```

Arguments are supplied using signed statements. Each statement is fed into the CVM, and evaluated within the rules of the CVM. If the statement is valid, then the actions are applied, the state is updated, and a receipt is returned to the sender.

```ts
type WitnessEntry = [
  stamp   : number,   // A UTC timestamp, in seconds.
  prog_id : string,   // An identifier that calls the program.
  ...args : Literal[] // The arguments to supply to the program.
]
```

Currently, the CVM only supports one method, and that is the `endorse` method. This method is designed to accept a number of signatures, then execute an action based on a quorum of signatures being reached. The threshold for this quorm is defined in the proposal terms.

The `endorse` method uses that are designed to be easy to work with. They are inspired by `NIP-26` delegation proofs, and can support an optional query string to provide additional parameters.

```ts
// Includes a reference id, pubkey, proof id, signature and timestamp.
'b92e904d8819b670761e903f3d788da3ccea2db1ed9253d9fdbab427fe87022a9997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be553ae992fa3b9a7fd6b6792936c2a6e6dcfbb3f091e2994df0c5cdb901e92e4abccb7ef9408028283a08c32e199036755c2401ddec831f6fad244c7aa7af8e7d4dff691c97add18871d32ec3c6c487f2433f51bf4ef3d9b2d58459aeff3b8016?stamp=1700172943'
```

Also, proofs use the same signing method as nostr notes, so technically any proof can be converted into a valid nostr note, and vice-versa. Valid proofs can also be constructed usings nostr-based signing devices (such as `NIP-07` based extensions).

```ts
// A parsed proof will look like this:
interface ProofData {
  ref    : string
  pub    : string
  pid    : string
  sig    : string
  params : string[][]
}
```

The CVM is designed to be extensibe. It will support many hooks and cross-platform integrations in the future. It is also a work in progress, so expect bugs.

## Deposits

Deposits are the most magical part of the protocol, and a good amount of engineering has been poured into their construction.

Each deposit account is a time-locked 2-of-2 taproot address. All deposits are guaranteed refundable, and the script path is only revealed in a worst-case scenario.

In addition, this address is constructed using an extended version of the musig2 protocol, optimized for non-interactive signing a batch of transactions. This protocol is compatible with BIP327 and does not comprimise on any of the security features in the specification.

```ts
interface DepositData {
  agent_id     : string
  agent_key    : string
  agent_pn     : string
  block_hash   : string | null
  block_height : number | null
  block_time   : number | null
  confirmed    : boolean
  covenant     : CovenantData | null
  created_at   : number
  expires_at   : number | null
  deposit_id   : string
  deposit_key  : string
  return_tx    : string
  scriptkey    : string
  sequence     : number
  settled      : boolean
  settled_at   : number | null
  spent        : boolean,
  spent_at     : number | null
  spent_txid   : string | null
  status       : DepositStatus
  txid         : string
  updated_at   : number
  value        : number
  vout         : number
}
```

It is important to note that a deposit can be released from one contract, and signed to another, without requiring an on-chain transaction. This is particularly useful if a contract expires or is otherwise cancelled, as the deposits can be reused immediately.

The caveat with this is that there is currently no revocation protocol in place for past covenants, so technically the agent has a limited opportunity to double-spend. There are plans to impove the off-chain use of deposits in a future version of the protocol.

```ts
type DepositStatus =
'reserved' | // An account has been reserved, no deposit registered.
'pending'  | // Deposit is registered in mempool and ready for signing.
'stale'    | // Deposit is stuck in mempool, must wait for confirmation.
'open'     | // Deposit is confirmed and ready for signing
'locked'   | // Deposit is currently locked to a covenant.
'spent'    | // Deposit has been spent and is awaiting confirmation.
'settled'  | // Deposit spending tx has been confirmed.
'expired'  | // Deposit time-lock is expired, no longer secured.
'error'      // Something went wrong, may need manual intervention.
```

When a contract is settled, it will appear on the blockchain as a simple P2TR (Pay to Taproot) transaction. No information about the contract, its depositors, or its participating members, are ever revealed.

## Covenants

A covenant is created using a custom protocol that wraps the musig2 protocol, and allows us to perform batch signing of transactions. It involves the use of a `root` nonce value for each signing member, which is then further tweaked in a non-interactive way. Each tweaked nonce value is then used in a standard musig2 signing session.

In regards to scaling, the protocol is O(1) for the coordinated negotiation of root nonces, requires O(n = outputs) partial signatures from each depositor, and O(n * m = depositors) for verification of signatures by the agent.

The protocol is relatively simple:

* All parties compute a hash that commits to the full terms of the contract.
  > Ex: hash340('root_nonce', serialize(contract_terms))
* Each member uses this hash to produce a root nonce value using BIP340 nonce generation.
* The agent includes their root public nonce value with the contract.
* For _each_ transaction, the depositor performs the following:
  - The depositor computes a second commitment that includes both root pnonces, plus the transaction.
    > Ex: hash340('contract/root_tweak', depositor_root_pnonce, agent_root_pnonce, sighash(tx))
  - This second hash is used to tweak the root pnonce for both the depositor and the agent.
  - The new pnonce values are used to compute a musig2 signing session, plus partial signature for the transaction.
* Each depositor delivers their pubkey, root pnonce value and payload of signatures to the agent.
* The agent can select a particular transaction, compute the tweak and musig context, then finalize the signature.

The purpose of the root nonce value is to guarantee that each derived nonce value is computed fairly, regardless of whom performs the computation. Each tweak extends the commitment of the root nonce value to the specific transaction being signed.

The root nonce value is never used directly in any signing operation. Each partial signature is computed using a derived nonce, via the standard musig2 protocol. This includes a full commitment to the session state and tweaked nonce values.

```ts
export interface CovenantData {
  cid    : string
  pnonce : string
  psigs  : [ string, string ][]
}
```

Each signature is flagged using the sighash flag ANYONECANPAY, allowing each deposit to be included among any combination of other inputs signed to the contract. Once all deposits and covenants have been collected for a given contract (and verified by the agent), the contract is considered active.

## Signatures and Signing Devices

The entire protocol, software, and supporting libraries have been designed from the ground-up to incorprate signing devices at all costs. Every interaction with a user's private key is done with the concept of a signing device in mind, and all signature methods in the procotol **require** a signing device as input.

In addition, the protocol is designed with the assumption that the contract agent is a dirty scoundrel who will swindle your private keys away from you using the worst tricks imaginable. All signature methods in the protocol **require** a signing device to generate nonce values and perform key operations, and **zero** trust is given to any counter-party during the signing process.

Even the musig part of the protocol has been extended to require secure nonce generation *within the device* as part of the signing process.

However, since we are using state-of-the-art cryptography, there is a lack of devices out there that can deliver what we need in order to build the best escrow platform on the planet.

Therefore included as part of the escrow-core library is a reference implementation of a software-based signing device.

This purpose of this signer is to act as a place-holder in the protocol, and clearly define what interactions take place, what information is exchanged, and what cryptographic primitives are required.

```ts
class Signer {
  // Generates a signing device from a random 32-byte value.
  static generate (config ?: SignerConfig) : Signer
  // Generates a signing device from the sha-256 hash of a passphrase.
  static seed (seed : string, config ?: SignerConfig ): Signer;
  // Provides a signing device for a given secret and configuration.
  constructor(secret: Bytes, config?: SignerConfig);
  // Provides a sha256 hash of the public key.
  get id(): string;
  // Provides the x-only public key of the device.
  get pubkey(): string;
  // Derives a key-pair from a derivation path. Accepts numbers and strings.
  derive(path: string): Signer;
  // Computes a shared-secret with the provided public key/
  ecdh(pubkey: Bytes): Buff;
  // Generates a nonce value for a given message, using BIP340.
  gen_nonce(message: Bytes, options?: SignerOptions): Buff;
  // Performs an HMAC operation using the device's internal secret.
  hmac(message: Bytes): Buff;
  // Produces a musig2 partial signature using the supplied context.
  musign(context: MusigContext, auxdata: Bytes, options?: SignerOptions): Buff;
  // Produces a BIP340 schnorr signature using the provided message.
  sign(message: Bytes, options?: SignerOptions): string;
}
```

There are three main primitives that are required in order to use the protocol:

- Schnorr signatures (BIP340).
- Musig signatures (BIP327, plus BIP340 nonce generation).
- Additional tweaks during nonce generation (for the batch covenant signing).

There's also a few neat tricks planned for a future release, so the reference signer comes packed with extra goodies.

The current Signer API represents what a first-class signing device should be able to do. A future version of the API may require methods for performing internal validation, as trusting third-party software for validation of cryptographic proofs is not a good practice.

## Escrow Client

In addition to the core protocol, this repository includes a client library for communicating with our escrow server.

```ts
export default class EscrowClient {
  constructor (
    signer   : Signer, 
    options ?: ClientOptions
  )

  contract: {
    cancel : (cid: string)             => Promise<EscrowContract>,
    create : (proposal : ProposalData) => Promise<EscrowContract>,
    list   : ()                        => Promise<EscrowContract[]>
    read   : (cid: string)             => Promise<EscrowContract>
    status : (cid: string)             => Promise<EscrowContract>
  }

  covenant: {
    add    : (
      contract : ContractData | EscrowContract, 
      deposit  : DepositData  | EscrowDeposit
    ) => Promise<EscrowDeposit>
    list   : (cid : string)        => Promise<EscrowDeposit[]>
    remove : (deposit_id : string) => Promise<EscrowDeposit>
  }

  deposit: {
    close: (
      address : string, 
      deposit : DepositData | EscrowDeposit,
      txfee  ?: number | undefined
    ) => Promise<EscrowDeposit>
    create: (
      agent_id  : string, 
      agent_key : string, 
      sequence  : number,
      txid      : string,
      options  ?: DepositConfig
    ) => Promise<DepositTemplate>
    list     : () => Promise<EscrowDeposit[]>
    read     : (deposit_id : string)        => Promise<EscrowDeposit>
    register : (template : DepositTemplate) => Promise<EscrowDeposit>
    request  : (params ?: Record)           => Promise<DepositInfo>
    status   : (deposit_id : string)        => Promise<EscrowDeposit>
  }

  oracle: {
    broadcast_tx   : (txhex: string)      => Promise<Resolve<string>>
    fee_estimates  : ()                   => Promise<OracleFeeEstimate>
    get_fee_target : (target: number)     => Promise<number>
    get_tx_data    : (txid: string)       => Promise<OracleTxData | null>
    get_spend_out  : (query: OracleQuery) => Promise<OracleSpendData | null>
  }

  witness: {
      list : (cid: string) => Promise<WitnessData[]>
      read : (wid: string) => Promise<WitnessData>
      submit: (
        cid     : string, 
        witness : WitnessEntry
      ) => Promise<EscrowContract>
  }
}
```

More documentation coming soon!

## Whitepaper

There is work being done on a white-paper that focuses on the technical details of the protocol (including the good, bad, and ugly) in order to make things official and invite the sweet wrath of academic scrutiny.

## Development / Testing

The documentation for development and testing is currently being fleshed out for an open beta release.

If you want to see a naive end-to-end demonstration of the of the protocol, you can use the follwoing command:

```bash
## Using Yarn:
VERBOSE=true yarn test
## Using NPM:
VERBOSE=true npm run test
```

This should spin up an isolated `regtest` version of Bitcoin core (which comes packaged with the repo), and run a flurry of methods which exercise the entire protocol. The full end-to-end test is located in `test/src/tests/e2e.test.ts`.

Over the next month, we'll be adding more concrete examples using the `EscrowClient`, plus opening our escrow server to public beta on `testnet` and `mutinynet`.

Please stay tuned!

## Issues / Questions / Comments

Please feel free to post any kind of issue on the tracker. All feedback is welcome.

## Contribution

Help wanted. All contributions are welcome. :-)

## Resources

Nearly the entire code-base has been built from scratch, with only one hard third-party dependency and a couple soft dependencies.

**noble-curves**  

Best damn elliptic curve library. Lightweight, independently audited, optimized to hell and back. Works across all platforms. Even deals with the nightmare that is webcrypo. There is no second best. Credit to Paul Miller.

https://github.com/paulmillr/noble-curves  

**noble-hashes**  

Paul's hashing library is also great, and performs synchronous operations. Credit to Paul Miller.

https://github.com/paulmillr/noble-hashes  

**zod**  

The best run-time validation library, also the best API of any method library. Turns javascript into a some-what respectable language. The error output can be the stuff of nightmares though. Credit to Colin McDonnel.

https://github.com/colinhacks/zod  

**tapscript**  

My humble taproot library and grab-bag of bitcoin related tools. Currently using a development version that has yet-to-be released due to undocumented changes in the API. 

https://github.com/cmdruid/tapscript  

**musig2**  

Reference implementation of the Musig2 protocol with a few additional features. However I do not implement the death star optimization.

https://github.com/cmdruid/musig2  

**crypto tools**  

Provides a full suite of cryptographic primities and other useful tools. Wraps the noble-curve and noble-hash libraries (and cross-checks them with other implementations). Also provides an extended protocol for BIP32 key-derivation that supports strings and urls.

https://github.com/cmdruid/crypto-tools  

**buff**  

The swiss-army-knife of byte manipulation. Such a fantastic and invaluable tool. Never leave home without it.

https://github.com/cmdruid/buff  

**core command**  

Not a run-time dependency, but I use this to incorporate bitcoin core directly into my test suite. I also use it to mock-up core as a poor-man's electrum server. Acts as a daemon wrapper and CLI tool, provides a full wallet API, faucets, and can run bitcoin core natively within a nodejs environment (which is pretty wild).

https://github.com/cmdruid/core-cmd  

# Footnote

My inspiration for this project comes from the Bitcoin space, and the incredibly talented people that keep it alive. From them I gained my knowledge and spirit, and for that I am grateful.

I wish for Bitcoin to win all the marbles; and become the new global reserve marbles that we all fight over. I firmly believe it will make the world a better place, and bring society towards a new golden age. Maybe we will become space-faring apes that reach beyond the moon.
