Kaspa桌面插件(iOS)5.14

5.14更新

⬆️显示效果⬆️
⬆️显示效果⬆️
//使用方法:
//                 1、手机上下载安装Scriptable;应用商店地址可复制去打开或者直接去搜https://apps.apple.com/cn/app/scriptable/id1405459188
//                 2、手机桌面空白出长按,引出左上角+号,点添加;
//                 3、出现的界面里下拉找到刚刚安装的Scriptable,选中后右滑到最大的显示效果,按下面添加小组件;
//                 4、进入Scriptable,选择左上角或者右上角“+”号将本文全部复制进去,随后按右上角Done;
//                 5、长按刚刚添加到桌面的小工具选择刚刚保存的脚本,等一会儿就可以显示了;
//⚠️⚠️⚠️需科学上网环境,后面应该会考虑设置Server,我也在等rust😂
//你们要是想投喂也是可以的,一块两块不嫌少 十万八万不嫌多 🍺 kaspa:qpz2zwxd4krj8ju3q9nueu5yc7hjld0z6c7ythrrdd0k3awy3td2c2hzvslke 👈❤️
//另外有丰富前端经验的欢迎拿去砸碎重来只要做好记得发我用

//👇你的钱包地址👇
const walletAddresses = [
  "kaspa:qqetp7ct8kqss99fxmymyz5t3fezppxp0t58wl6pawp27elqd46uudme00cl0",
   "kaspa:qpjw6xx9x5dv90ju68msey9p2s87efqk7segu9k4a4lrr024qtthukum5kgyy",
   "kaspa:qpwxu5fwzj8etlngl5kyvcpx8yk3jkqwrtvga6f33xe97f4x5kvq6z8swne8f",
  // 可添加多个钱包地址,建议不超过三条
];

//👆根据上面格式,在双引号内填入钱包地址,考虑到合并交易特性,每次合并之后你可能需要在这里更新你的钱包地址获取最新余额

const apiDomain = "https://api.kaspa.org";
const coingeckoDomain = "https://api.coingecko.com";
const apiUrls = {
  blockreward: `${apiDomain}/info/blockreward`,
  perGHreward: "https://api.minerstat.com/v2/coins?list=KAS",
  price: `${coingeckoDomain}/api/v3/simple/price?ids=kaspa&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true&precision=6`,
  hashrate: `${apiDomain}/info/hashrate`,
  coinsupply: `${apiDomain}/info/coinsupply`,
  //balance: `${apiDomain}/addresses/%walletAddress%/balance`, 
  halving: `${apiDomain}/info/halving`,
  marketCapRank: `${coingeckoDomain}/api/v3/coins/kaspa?tickers=false&market_data=true&community_data=false&developer_data=false&sparkline=false`
};

async function fetchData(url) {
  const response = await new Request(url).loadString();
  return JSON.parse(response);
}

const blockrewardData = await fetchData(apiUrls.blockreward);
const priceData = (await fetchData(apiUrls.price)).kaspa;
const hashrateData = await fetchData(apiUrls.hashrate);
const coinsupplyData = await fetchData(apiUrls.coinsupply);
//const balanceData = await fetchData(apiUrls.balance);
const perGHrewardData = (await fetchData(apiUrls.perGHreward))[0];
const halvingData = await fetchData(apiUrls.halving);
const marketCapRankData = await fetchData(apiUrls.marketCapRank);
const marketCapRank = marketCapRankData.market_cap_rank;

const KAS_SYMBOL = "𐤊";

const widget = new ListWidget();
      widget.setPadding(16, 0, 0, 0);
      
const gradient = new LinearGradient();
      gradient.locations = [0, 1];
      gradient.colors = [
      new Color("#70dabf"),
      new Color("#87ebc8")
  ];
    widget.backgroundGradient = gradient;
  
//title      

const titleBox = widget.addStack();
      titleBox.setPadding(0, 16, 0, 16);

const title = titleBox.addText("                  Kaspa");
      title.textColor = new Color("#fff");
      title.font = new Font("HelveticaNeue-Bold", 25);

      titleBox.addSpacer(null);

const blockrewardBox = titleBox.addStack();
blockrewardBox.layoutVertically();
blockrewardBox.spacing = 6;

const blockrewardTitle = blockrewardBox.addText("    区块奖励");
blockrewardTitle.textColor = new Color("#fff");
blockrewardTitle.font = Font.systemFont(10);

const blockreward = blockrewardBox.addText(blockrewardData.blockreward.toFixed(2).toString() + ` ${KAS_SYMBOL}`);
blockreward.textColor = new Color("#fff");
blockreward.font = Font.boldSystemFont(15);

const contentBox = widget.addStack();
      contentBox.backgroundColor = new Color("#F4F7FA");
      contentBox.cornerRadius = 18;
      contentBox.spacing = 15;
      contentBox.setPadding(16, 16, 16, 16);
      contentBox.layoutVertically();

//row1
const row1 = contentBox.addStack();
      row1.spacing = 15;    
      

const priceBox = row1.addStack();
const priceWrap = priceBox.addStack();
      priceWrap.spacing = 6;
      priceWrap.layoutVertically();
for (const key in priceData) {
    if(key === 'usd'){
        const row = priceWrap.addStack();
        row.spacing = 6;
        row.layoutVertically();
        const keyText = row.addText("当前价格");
        keyText.textColor = Color.gray();
        keyText.font = Font.systemFont(12);
        const valueText = row.addText(('$ ') + priceData[key].toFixed(4).toString());
        valueText.textColor = Color.black();
        valueText.font = Font.boldSystemFont(14);
    }
  
}
//row1.addSpacer(5);

const changeBox = row1.addStack();
const changeWrap = changeBox.addStack();
changeWrap.spacing = 5;
changeWrap.layoutVertically();

for (const key in priceData) {
    if (key === 'usd_24h_change') {
        let row = changeWrap.addStack()
        row.spacing = 6
        row.layoutVertically();
        let keyText = row.addText("24H涨跌")
        keyText.textColor = Color.gray();
        keyText.font = Font.systemFont(12);

        let value = priceData[key]
        let valueText
        if (value >= 0) {
            valueText = row.addText("+" + value.toFixed(2).toString() + '%' + ' ↑')
            valueText.textColor = Color.green()
            valueText.font = Font.boldSystemFont(14);
        } else {
            valueText = row.addText(value.toFixed(2).toString() + '%' + ' ↓' )
            valueText.textColor = Color.red()
            valueText.font = Font.boldSystemFont(14); 
        }
    }
}
//row1.addSpacer(5);

const volWrap = row1.addStack();
      volWrap.spacing = 6;
      volWrap.layoutVertically();
const volText = volWrap.addText("24H成交");
      volText.textColor = Color.gray();
      volText.font = Font.systemFont(12);
const volValue = priceData['usd_24h_vol'] / 1e6;
const volValueText = volWrap.addText('$ ' + volValue.toFixed(2).toString() + 'M');
      volValueText.textColor = Color.black();
      volValueText.font = Font.boldSystemFont(14);

      //row1.addSpacer(null);
      

const capWrap = row1.addStack();      
      for (const key in priceData){
      
      if (key === 'usd_market_cap'){
        let row = row1.addStack()
        row.spacing = 6
        row.layoutVertically()
        let keyText = row.addText("当前市值")
        keyText.textColor = Color.gray()
        keyText.font = Font.systemFont(12)
        let value = priceData[key]
        let valueText
        if (value >= 1e9) {
            value = value / 1e9
            valueText = row.addText(value.toFixed(1).toString() + ' B')
        }
        else if (value >= 1e6) {
            value = value / 1e6
            valueText = row.addText(value.toFixed(1).toString() + ' M')
        }
        else {
            valueText = row.addText(value.toFixed(2).toString() + ' USD')
        }
        valueText.textColor = Color.black()
        valueText.font = Font.boldSystemFont(14)
    }
      
      }
      
      
//row2

row2 = contentBox.addStack();
row2.spacing = 15;
      
const hashrateWrap = row2.addStack();
      hashrateWrap.spacing = 6;
      hashrateWrap.layoutVertically();
for (const key in hashrateData) {
    if (key === 'hashrate') {
        const hashrate = Math.round(hashrateData[key]);
        let displayHashrate, unit;

        if (hashrate > 1000) {
            displayHashrate = (hashrate / 1000).toFixed(2);
            unit = ' PH/s';
        } else {
            displayHashrate = hashrate.toFixed(2);
            unit = ' TH/s';
        }

        const row = hashrateWrap.addStack();
        row.spacing = 6;
        row.layoutVertically();
        const keyText = row.addText("全网算力");
        keyText.textColor = Color.gray();
        keyText.font = Font.systemFont(12);
        const valueText = row.addText(displayHashrate.toString() + unit);
        valueText.textColor = Color.black();
        valueText.font = Font.boldSystemFont(14);
    }
}
//row2.addSpacer(null);

const perGHrewardWrap = row2.addStack();
      perGHrewardWrap.spacing = 6;
      perGHrewardWrap.layoutVertically();
const rewardKey = 'reward';
if (perGHrewardData.hasOwnProperty(rewardKey)) {
  const perGHreward = perGHrewardData[rewardKey] * 1e9 * 24;
  let displayPerGHreward;

  const row = perGHrewardWrap.addStack();
  row.spacing = 6;
  row.layoutVertically();
  const keyText = row.addText("收益/日/GH");
  keyText.textColor = Color.gray();
  keyText.font = Font.systemFont(12);
  const valueText = row.addText(perGHreward.toFixed(2).toString() + ` ${KAS_SYMBOL}`);
  valueText.textColor = Color.black();
  valueText.font = Font.boldSystemFont(14);
}

//row2.addSpacer(null);

const supplyBox = row2.addStack();
const circulatingSupply = coinsupplyData.circulatingSupply;
const maxSupply = coinsupplyData.maxSupply;
const percentage = (circulatingSupply / maxSupply) * 100;
const row = supplyBox.addStack();
row.spacing = 6;
row.layoutVertically();
const keyText = row.addText("已挖占比");
keyText.textColor = Color.gray('');
keyText.font = Font.systemFont(12);
const valueText = row.addText(`${percentage.toFixed(2)} %`);
valueText.textColor = Color.black();
valueText.font = Font.boldSystemFont(14);

const marketCapRankRow = row2.addStack();
marketCapRankRow.spacing = 6;
marketCapRankRow.layoutVertically();

const marketCapRankKeyText = marketCapRankRow.addText("   市值排名");
marketCapRankKeyText.textColor = Color.gray('');
marketCapRankKeyText.font = Font.systemFont(12);

const marketCapRankValueText = marketCapRankRow.addText(`    # ${marketCapRank}`);
marketCapRankValueText.textColor = Color.black();
marketCapRankValueText.font = Font.boldSystemFont(14);

//row2.addSpacer(null);
      
//row3
const row3 = contentBox.addStack();
      row3.spacing = 15;
      
const nextHalvingTimestamp = halvingData.nextHalvingTimestamp;
const nextHalvingDate = new Date(nextHalvingTimestamp * 1000);
const nextHalvingAmount = halvingData.nextHalvingAmount;

const now = new Date();
const msToNextHalving = nextHalvingDate - now;
const daysToNextHalving = msToNextHalving / (1000 * 60 * 60 * 24);

const nextHalvingWrap = row3.addStack();
nextHalvingWrap.spacing = 16;
nextHalvingWrap.layoutHorizontally();

const nextHalvingDateRow = nextHalvingWrap.addStack();
nextHalvingDateRow.spacing = 6;
nextHalvingDateRow.layoutVertically();
const nextHalvingDateKeyText = nextHalvingDateRow.addText("下次减产");
nextHalvingDateKeyText.textColor = Color.gray();
nextHalvingDateKeyText.font = Font.systemFont(12);
const nextHalvingDateValueText = nextHalvingDateRow.addText(nextHalvingDate.toLocaleDateString());
nextHalvingDateValueText.textColor = Color.black();
nextHalvingDateValueText.font = Font.boldSystemFont(14);

row3.addSpacer(null);

const nextHalvingDateCountRow = nextHalvingWrap.addStack();
nextHalvingDateCountRow.spacing = 6;
nextHalvingDateCountRow.layoutVertically();
const nextHalvingDateCountKeyText = nextHalvingDateCountRow.addText("距减产");
nextHalvingDateCountKeyText.textColor = Color.gray();
nextHalvingDateCountKeyText.font = Font.systemFont(12);
const nextHalvingDateCountValueText = nextHalvingDateCountRow.addText(daysToNextHalving.toFixed(1).toString() + " 天");
nextHalvingDateCountValueText.textColor = Color.black();
nextHalvingDateCountValueText.font = Font.boldSystemFont(14);
const daysInCycle = 30; 


const percentageToNextHalving = (daysToNextHalving / daysInCycle) * 100;


let countdownColor;
if (percentageToNextHalving >= 60) {
  countdownColor = Color.black();
} else if (percentageToNextHalving >= 30) {
  countdownColor = Color.yellow();
} else {
  countdownColor = Color.red();
}


nextHalvingDateCountValueText.textColor = countdownColor;

row3.addSpacer(null);

const nextHalvingAmountRow = nextHalvingWrap.addStack();
nextHalvingAmountRow.spacing = 6;
nextHalvingAmountRow.layoutVertically();
const nextHalvingAmountKeyText = nextHalvingAmountRow.addText("减产后奖励");
nextHalvingAmountKeyText.textColor = Color.gray();
nextHalvingAmountKeyText.font = Font.systemFont(12);
const nextHalvingAmountValueText = nextHalvingAmountRow.addText(nextHalvingAmount.toFixed(2).toString() + ` ${KAS_SYMBOL}     `);
nextHalvingAmountValueText.textColor = Color.black();
nextHalvingAmountValueText.font = Font.boldSystemFont(14);

//row4
const row4 = contentBox.addStack();
row4.spacing = 15;

const balanceBox = row4.addStack();
balanceBox.layoutVertically();
balanceBox.spacing = 6;


  const time = new Date();
  const balanceKeyText = balanceBox.addText("钱包余额 " + time.toLocaleDateString() + " " + time.toLocaleTimeString());
  balanceKeyText.textColor = Color.gray();
  balanceKeyText.font = Font.systemFont(12);
  balanceKeyText.spacing=6;

const walletBalanceFontSize = walletAddresses.length <= 2 ? 16 : 15;
const walletValueFontSize = walletAddresses.length <= 2 ? 15 : 14;


for (
  
  const walletAddress of walletAddresses) {
  const balanceData = await fetchData(`${apiDomain}/addresses/${encodeURIComponent(walletAddress)}/balance`);
  const balance = balanceData.balance / 1e8;
  const balanceFormatted = new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(balance
  
  );
  

  const walletBalanceBox = balanceBox.addStack();
  walletBalanceBox.spacing = 6;
  walletBalanceBox.layoutHorizontally();

const price = priceData.usd;
const walletValue = balance * price;
const walletValueFormatted = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(walletValue);



let balanceEmoji;
if (balance >= 1e9 && balance < 10e9) {
  balanceEmoji = "🔱";
} else if (balance >= 100e6 && balance < 1e9) {
  balanceEmoji = "🐋";
} else if (balance >= 10e6 && balance < 100e6) {
  balanceEmoji = "🐳";
} else if (balance >= 1e6 && balance < 10e6) {
  balanceEmoji = "🦈";
} else if (balance >= 100e3 && balance < 1e6) {
  balanceEmoji = "🐬";
} else if (balance >= 10e3 && balance < 100e3) {
  balanceEmoji = "🐟";
} else if (balance >= 1e3 && balance < 10e3) {
  balanceEmoji = "🐙";
} else if (balance >= 100 && balance < 1e3) {
  balanceEmoji = "🦀";
} else {
  balanceEmoji = "🦐";
}

const walletBalanceText = walletBalanceBox.addText(`${balanceEmoji} ${balanceFormatted} 𐤊`);
  walletBalanceText.textColor = new Color("#70dabf");
  walletBalanceText.font = new Font("Menlo-Bold", walletBalanceFontSize);

  const walletValueText = walletBalanceBox.addText(walletValueFormatted);
  walletValueText.textColor = Color.gray();
  walletValueText.font = new Font("Menlo", walletValueFontSize);
  
  
}



// API References
const apiBox = widget.addStack();
apiBox.setPadding(8, 8, 0, 0);
apiBox.layoutVertically();
apiBox.addSpacer();

const apiText = apiBox.addText("/* Kaspa, CoinGecko, Minerstat API/");
apiText.textColor = new Color("#808080");
apiText.font = new Font("Menlo-Regular", 7);

const verText = apiBox.addText("-更新于2023年5月14日-");
verText.textColor = new Color("#000");
verText.font = new Font("Menlo-Regular", 7);

const twitterBox = widget.addStack();
twitterBox.spacing = 6;
twitterBox.setPadding(0, 8, 16, 0);
twitterBox.addSpacer();

const heart = twitterBox.addText("❤️");
heart.textColor = new Color("#fff");
heart.font = new Font("HelveticaNeue-Bold", 12);

const twitterImg = twitterBox.addImage(twitterLogo());
twitterImg.imageSize = new Size(16, 16);
const twitterUsername = twitterBox.addText("@Dodo13080274   ");
twitterUsername.textColor = new Color("#fff");
twitterUsername.font = new Font("HelveticaNeue-Bold", 14);



if (!config.runsInWidget) {
    await widget.presentLarge();
  }

widget.url = "https://twitter.com/Dodo13080274";

Script.setWidget(widget);
Script.complete();


function twitterLogo() {
  const data = Data.fromBase64String(
    "iVBORw0KGgoAAAANSUhEUgAAABsAAAAWCAYAAAAxSueLAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAErSURBVHgBvZWBdYIwEIYvvA7gCGxQNigjOAIblBHqBt0AukE7QegEugFsoBv8XkzwRQyYA/R773+RwOU/7yAheiGKFgJgw8OWlbqpg1Lq91FQ5gIlRjmrxT2tu7dxY8VK/cCatY81NMGIpzQxiRf/zspY+iaLcTTF0bBMYp9+pu2gDMVYtCu5hHq4gA48ZObygNkW8VR93Ju3xo41XNhcmwZ3PP65knQk4z84C/uSrE3er594RqbhmJH5I079DzUwy2ll+AO/eviv/o7Wp/EvEi+D5gmGP5N3uZwFwlvQHFIK/TOPD9aBllNztbrJJzibEstpEbflXQy/sYyCJMD2TrOOkPFFc4A9RvRTjWAPPOnWVUoWr2AbKy2bZmUkAbZkpk/7CIMjRo6fKc6UxWq3r/OykAAAAABJRU5ErkJggg=="
  );
  return Image.fromData(data);
}



Subscribe to Dodo
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.