# .derupt-ext

{% hint style="info" %}
Work in Progress
{% endhint %}

```
;; title: derupt-ext
;; version: 1.3.1
;; summary: Derupt Extension Contract (sample extension for reference)

;; Derupt Extension Example - Send passed amount of CC to passed principal
(impl-trait 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.derupt-ext-trait.derupt-ext)

(use-trait cryptocash-token-trait 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.cryptocash-token-trait.cryptocash-token)
(use-trait cryptocash-core-trait 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.cryptocash-core-trait.cryptocash-core)

(use-trait sip-009-trait-ft-standard 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.sip-009-trait-nft-standard.sip-009-trait)
(use-trait sip-010-trait-ft-standard 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.sip-010-trait-ft-standard.sip-010-trait)
(use-trait sip-013-trait-ft-standard 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.sip-013-trait-sft-standard.sip-013-trait)

;; Errors
(define-constant ERR-UNAUTHORIZED (err u100))
(define-constant ERR-NOTFOUND (err u101))
(define-constant ERR-WRONG-CC-TOKEN-VERSION (err u102))

(define-data-var ext-owner principal tx-sender)

(define-map ext-meta principal 
  { 
    name: (string-ascii 24),
    description: (string-ascii 256),
    image: (string-ascii 256)
  }
)

(define-read-only (get-ext-metadata) 
  (ok (unwrap! (map-get? ext-meta (var-get ext-owner)) ERR-NOTFOUND))
)

(define-public (update-ext-owner (new-ext-owner principal)) 
  (begin 
    (asserts! (is-eq tx-sender (var-get ext-owner)) ERR-UNAUTHORIZED)
    (asserts! (is-standard new-ext-owner) ERR-UNAUTHORIZED)
    (var-set ext-owner new-ext-owner)
    (print {prev-owner: tx-sender, new-owner: new-ext-owner})
    (ok true)
  )
)

(define-read-only (get-ext-owner) 
  (ok (var-get ext-owner))
)

(define-public (update-ext-metadata (name (optional (string-ascii 24))) (description (optional (string-ascii 256))) (image (optional (string-ascii 256)))) 
  (let 
    (
      (meta (map-get? ext-meta (var-get ext-owner)))
      (prev-name (unwrap! (get name meta) ERR-NOTFOUND))
      (prev-description (unwrap! description ERR-NOTFOUND))
      (prev-image (unwrap! image ERR-NOTFOUND))
    ) 
    (asserts! (is-eq tx-sender (var-get ext-owner)) ERR-UNAUTHORIZED)
    (match name value (map-set ext-meta (var-get ext-owner) {name: value, description: prev-description, image: prev-image}) false)
    (match description value (map-set ext-meta (var-get ext-owner) {name: prev-name, description: value, image: prev-image}) false)
    (match image value (map-set ext-meta (var-get ext-owner) {name: prev-name, description: prev-description, image: value}) false)
    (print { prev-name: prev-name, new-name: (unwrap! name ERR-NOTFOUND), prev-description: prev-description, description: (unwrap! description ERR-NOTFOUND), prev-image: prev-image, image: (unwrap! image ERR-NOTFOUND)})
    (ok true)
  )
)


;; Get derupt-core-contract - used to verify call origin
(define-private (get-derupt-core-contract)
  (contract-call? 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.derupt-feed get-derupt-core-contract) 
)

;; Get cc-token-contract - used to get active cc token contract
(define-private (get-cc-token-contract)
  (contract-call? 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.derupt-feed get-cc-token-contract) 
)

;; Transfer CryptoCash
(define-public (cryptocash-transfer (cc-token-contract <cryptocash-token-trait>) (amount uint) (recipient principal))
  (contract-call? cc-token-contract transfer amount tx-sender recipient none)
)

;; Execute Extension Function
(define-public (exec-ext-func 
    (extras (optional (list 10 
      {
        stringutf8: (optional (string-utf8 256)), 
        stringascii: (optional (string-ascii 256)), 
        uint: (optional uint), 
        int: (optional int), 
        principal: (optional principal), 
        bool: (optional bool),
        buff: (optional (buff 34)),
        proxy: (optional (buff 2048)),
        cryptocash-token-contract: (optional <cryptocash-token-trait>),
        cryptocash-core-contract: (optional <cryptocash-core-trait>),
        sip-009-contract: (optional <sip-009-trait>),
        sip-010-contract: (optional <sip-010-trait>),
        sip-013-contract: (optional <sip-013-trait>)
      }))
    )
  )
    (let
      ;;get and verify call is coming from current core.
      (
        (derupt-core-contract (unwrap! (get-derupt-core-contract) ERR-NOTFOUND))  
        (cc-token-address (unwrap! (get-cc-token-contract) ERR-WRONG-CC-TOKEN-VERSION)) 
        (cc-token-contract (unwrap! (get cryptocash-token-contract (element-at? (unwrap! extras ERR-NOTFOUND) u0)) ERR-NOTFOUND))  
        ;; Amount extraction from position x of expected tuple arguments
        (amount (unwrap! (unwrap! (get uint (element-at? (unwrap! extras ERR-NOTFOUND) u0)) ERR-NOTFOUND) ERR-NOTFOUND))  
        (recipient (unwrap! (unwrap! (get principal (element-at? (unwrap! extras ERR-NOTFOUND) u0)) ERR-NOTFOUND) ERR-NOTFOUND))  
      )
      (asserts! (is-eq contract-caller derupt-core-contract) ERR-UNAUTHORIZED)    
      (asserts! (is-eq (contract-of cc-token-contract) cc-token-address) ERR-NOTFOUND) 

      ;; perform cc transfer?
      (try! (cryptocash-transfer cc-token-contract amount recipient))

      ;; Print logging
      (print 
        { 
          event: "derupt-ext-message: Transfer CC Too", 
          tx-sender: tx-sender, 
          recipient: recipient,
          extras: extras,
          amount:amount
        }
      )
      (ok true)
    )
)

(map-insert ext-meta (var-get ext-owner) {name: "Transfer CC too", description: "Extension to Transfer an AMOUNT of CC to defined PRINCIPAL", image: "https://stackers.cc/cryptocash.png"})
```

## Extension Contract Metadata

The extension *contract metadata* represents the top level summary of the extension.

```json
{
  "name": "Transfer CC too",
  "description": "https://stackers.cc/derupt-ext-metadata.json",
  "image": "https://stackers.cc/more-cc.gif"
}
```

## Extension Description Metadata

The extension *description metadata* enables greater control over the integration and functionality of the Extension within the Derupt UX/UI, facilitating for you:

* Extension Information Summary (`info`):
  * A general Summary / Explanation of the Extension
* Availability for specific Core Operation (`ops`):
  * To enable use of the Extension by Derupt Core Operations
* Applicable Transaction Post Conditions (`postconditions`):
  * Set the appropriate type: `ft`, `nft`, and or `stx`
* Function Arguments from the User (`argsFromUser`)
  * To enable the applicable argument input fields to be rendered and supplied by the user. \
    (`render` set visibility of the argument input field to the user in the Extension options modal)\
    (`label` set the label you want to apply to the visible field)\
    (`order` set the rendered order of argument input fields)\
    (`optional` representative if input field is an optional input \[`false` means the argument input field is required, `true` means the argument input field is optional]) \
    \
    \&#xNAN;*Note: `argsFromUser` are passed as `extra` function arguments in core operation calls.*

```json
{
    "info": "Extension to Transfer a AMOUNT of CC to a PRINCIPAL (TESTNET)",
    "ops": {
        "send-message": false,
        "like-message": true,
        "dislike-message": true,
        "favorable-reply-message": true,
        "unfavorable-reply-message": true,
        "gift-message": true
    },
    "postconditions": [
        {
            "type": "ft",
            "contractAddress": "ST1ZK0A249B4SWAHVXD70R13P6B5HNKZAA0WNTJTR.cryptocash-token:cryptocash"
        }
    ],
    "argsFromUser": {
        "0": {
            "uint": {
                "render": true,
                "label": "Amount",
                "order": 0,
                "optional": false
            },
            "principal": {
                "render": true,
                "label": "Recipient Principal",
                "order": 1,
                "optional": false
            }
        }
    }
}
```

{% hint style="warning" %}
Extension Contract Metadata pointers is updated via `update-metadata`&#x20;
{% endhint %}

{% hint style="warning" %}
Extension Description Metadata is updated via `derupt-ext-metadata.json` \
(or equivalent)&#x20;
{% endhint %}

{% hint style="warning" %}
Extensions must follow[`.derupt-ext-trait`](/latest/contracts/.derupt-ext-trait.md) standard
{% endhint %}

{% hint style="warning" %}
Extension execution `exec-ext-func` function, taking `extras` as an argument. \
\
Developers should define`argsFromUser` to ensure specific fields are presented to the user during the presentation of `ExtensionModal` in order to collect users input if needed.
{% endhint %}

{% hint style="warning" %}
Users can have only 1 extension called, per core function call: eg

* can have 1 `ext` called during `send-message`
* can have 1 `ext` called during `like-message`&#x20;
* can have 1 `ext` called during `dislike-message`
* can have 1 `ext` called during `favorable-reply-message`
* can have 1 `ext` called during `unfavorable-reply-message`
* can have 1 `ext` called during `gift-message`

(note: users can change the enabled extension over time)
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.derupt.io/latest/contracts/.derupt-ext.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
