[JavaScript] ファイル名とファイルの中身を取得する

ブロックチェーン上に上げるために、ファイル名とファイルの中身を取得したい。

html

				<div class="control">
					<input id="file" name="file" type="file" />
				</div>
				// 省略
		<p>Please press the button.</p>
		<input type="submit" class="button is-link" id="btn" value="authorize" onclick="OnButtonClick();">

view: buttonを押すと処理を実行するように書いている(onChangeではない)

reader.readAsTextとした後に、reader.onload(ファイルの読み込み完了) 後に処理をする。

		let reader = new FileReader();
		let input = ""

		function OnButtonClick() {
			input = document.getElementById("file").files[0]
			reader.readAsText(input, 'UTF-8')
			reader.onload = ()=> {
	            main();	
	        };
						
		}
		async function main() {
			console.log(input.name)
			console.log(reader.result);
		}

なるほどー、割と簡単にできたなー

[NEM] Apostilleで実装したい

public apostilleとprivate apostilleがある

## open apostille
https://www.openapostille.net/detail/797ae3b488f7808bf3b7ad46c7f487f2b02645175f09256ca532eb74b274d319

Txhash: 797ae3b488f7808bf3b7ad46c7f487f2b02645175f09256ca532eb74b274d319
ファイル名: ジャパンカップ予想 — Apostille TX 797ae3b488f7808bf3b7ad46c7f487f2b02645175f09256ca532eb74b274d319 — Date 2017-11-25.docx

## transfer transaction:
http://chain.nem.ninja/#/transfer/797ae3b488f7808bf3b7ad46c7f487f2b02645175f09256ca532eb74b274d319

Message: 4e545903560fc41a6f8c9495ee7e7e18322973c50e9e2f4fbb91fa892343412586d9a808

### public apostilleの詳細
fe4e545903560fc41a6f8c9495ee7e7e18322973c50e9e2f4fbb91fa892343412586d9a808

fe 16進数
4e5459 apostilleを示す
0 public(privateは9)
3 hash algorithm sha256(1:md5, 2:sha1, 3:sha256, 8:sha3-256, 9:sha3-512などがある)
560fc41a6f8c9495ee7e7e18322973c50e9e2f4fbb91fa892343412586d9a808 hash

$ sha256sum “ジャパンカップ予想 — Apostille TX 797ae3b488f7808bf3b7ad46c7f487f2b02645175f09256ca532eb74b274d319 — Date 2017-11-25.docx”
560fc41a6f8c9495ee7e7e18322973c50e9e2f4fbb91fa892343412586d9a808 ジャパンカップ予想 — Apostille TX 797ae3b488f7808bf3b7ad46c7f487f2b02645175f09256ca532eb74b274d319 — Date 2017-11-25.docx

一致する
sha256sumコマンドはSHA-256を用いて、256ビット(64桁の16進数)を出力

NanoWalletではファイル名の記載されたトランザクションハッシュからハッシュ値が記録されたメッセージを取得し、
メッセージから取り出したハッシュ値とファイルのハッシュ値を付き合わせて完全性を証明している
存在証明はそのトランザクションのタイムスタンプを利用する
-> 上記の2つで、ある時点でこのファイルが存在していたと証明できる
アポスティーユはトランザクションの応用

#### NanoWalletで作成してみる

{"data":[
{"filename":"test.txt",
 "tags":"test",
  "fileHash":"fe4e545983efc827e551fcd0c8429a468a7c6c64f5f231b1221c3ecffdbfff00dacdd9a95aed46a4d30e88cf83dfdf9a49beb4a7e748bcde7465ac15e202a50ad28f44f606",
  "owner":"NDXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "fromMultisig":"NDIWUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "dedicatedAccount":"NCFYBGQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "dedicatedPrivateKey":"79e4a484XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "txHash":"bea36f12fe14a046ab849f8df097fbe238aae457e45a36854d800d8f45c52b33",
  "txMultisigHash":"",
  "timeStamp":"Sat, 18 Dec 2021 14:35:34 GMT"
 }]}

filename, tag, filehash, owner, fromMultisig, dedicatedAccount, dedicatedPrivtateKey, txHash, txMultisigHash, timeStamp

MessageHEX: 4e545903 5526798746c3bdabb663b681ed78c2f8ac0b13b275dc4f95d4941fc58d7258e0

$ sha256sum “sample — Apostille TX 52d76444c713f3f84e5c44107cce511d974a250b91c5c49a1323bfe838da0f5a — Date 2021-12-19.txt”
5526798746c3bdabb663b681ed78c2f8ac0b13b275dc4f95d4941fc58d7258e0 sample — Apostille TX 52d76444c713f3f84e5c44107cce511d974a250b91c5c49a1323bfe838da0f5a — Date 2021-12-19.txt

ダウンロードしたファイルのsha256でhash計算した値が、MessageのHash値と一致していることで、このファイルが、この時間にあったことを証明している。

ンンン、なるほどー

[NEM] mosaicで商品購入ページを作りたい

基本的にはsendと同じだが、商品を選択して、商品数を入力できるようにすれば良い

		<div class="card column">
			<center><input type="radio" name="art" value="1" checked></center>
		</div>
		<div class="card column">
			<center><input type="radio" name="art" value="2"></center>
		</div>
		<div class="card column">
			<center><input type="radio" name="art" value="3"></center>
		</div>

		<div class="field" width="90%" style="margin:20px">
			<label class="label">Amount</label>
			<div class="control ">
				<input class="input" size="3" type="number" id="amount" style="width: 33%;" placeholder="" value="1">
			</div>
		</div>

js: 商品情報を連想配列で持って、radioボタンが押された時に、配列の何番目かを取得すれば良い

		var products = [
			{name:"Rime ethics", price:"20"},
			{name:"Midnight Asia", price:"30"},
			{name:"Dreams & Struggle", price:"90"},
		]

		// 省略

		function OnButtonClick() {
			let checkValue = "";
			let elements = document.getElementsByName('art');
			for (let i = 0; i < elements.length; i++){
			    if (elements.item(i).checked){
			        checkValue = i;
			    } 
			}
			sendAmountNem = parseInt(products[checkValue]['price']) * amount.value;
			name = products[checkValue]['name'];
			if (!walletpassword.value || !privatekey.value) {
			    resArea.innerHTML = "Wallet Password、privatekeyを入力してください";
			} else {
			    main();
			}		
			
		}

割とやりたいことはできたか…

[NEM] Wallet情報の取得

var nem = require("nem-sdk").default;

const endpoint = nem.model.objects.create('endpoint')(nem.model.nodes.defaultMainnet, nem.model.nodes.defaultPort);

const mainnetAddress = '****'

async function main() {
	await nem.com.requests.account.data(endpoint, mainnetAddress).then(res => {
		console.log('balance:', res.account);
	}).catch(err => {
		console.log(err);
	});
}

main();

$ node wallet.js
balance: { address: ‘****’,
harvestedBlocks: 0,
balance: 00000000,
importance: 0,
vestedBalance: 00000000,
publicKey:
‘****’,
label: null,
multisigInfo: {} }

なるほどね、アカウントにいくら入ってるかってのは誰でも見れちゃうんだな

[JavaScript] inputに入力があれbuttonを押せるようにする

btn.disabled = true; でbuttonを制御します。
input.addEventListener(“change”, func); で btn.disabledの状態を変更する

let btn = document.getElementById('btn');
		let wallet = document.getElementById('wallet');
		let message = document.getElementById('message');
		let amount = document.getElementById('amount');
		let resArea = document.getElementById("resArea");
		btn.disabled = true; 
		wallet.addEventListener("change", stateHandle);
		amount.addEventListener("change", stateHandle);
		message.addEventListener("change", stateHandle);
		function stateHandle() {
		  if (wallet.value == "" || amount.value == "") {
		    btn.disabled = true; 
		  } else {
		    btn.disabled = false;
		  }
		}

		function OnButtonClick() {
			if (!wallet.value || !message.value || !amount.value) {
			    resArea.innerHTML = "Wallet Address、amount、messageを入力してください";
			} else {
			    main();
			}		
			
		}
		async function main() {
			console.log("送金完了しました")
			console.log(wallet.value)
			console.log(message.value)
			console.log(amount.value)
			resArea.innerHTML = "送金完了しました";
		}

最初

入力後

OK
これで実際に送金できるかテストする

しゃあああああああああああああああああああ
次はxem amountの取得かな

[NEM] node.jsでmosaicを送信

nem-sdkをインストールします
$ npm install nem-sdk

mainnetで送信します。

var nem = require("nem-sdk").default;

const endpoint = nem.model.objects.create('endpoint')(nem.model.nodes.defaultMainnet, nem.model.nodes.defaultPort);

async function main() {

    const toAddress = '';
    const sendAmount = 1;
    const sendMsg = 'Hello World!';
    const password = '';
    const privateKey = '';
    const common = nem.model.objects.create('common')(password, privateKey);
    const yourMosaicNamespace = 'capitalcoin';
    const yourMosaicName = 'hpscript';

    let transferTransaction = nem.model.objects.create('transferTransaction')(toAddress, sendAmount, sendMsg);

    const xemMozaic = nem.model.objects.create('mosaicAttachment')('nem', 'xem', 0);
    transferTransaction.mosaics.push(xemMozaic);

    const yourMosaic = nem.model.objects.create('mosaicAttachment')(yourMosaicNamespace, yourMosaicName, 10);
    transferTransaction.mosaics.push(yourMosaic);

    let mosaicDefinitionMetaDataPair = nem.model.objects.get('mosaicDefinitionMetaDataPair');
    nem.com.requests.namespace.mosaicDefinitions(endpoint, yourMosaic.mosaicId.namespaceId).then(res => {

        const neededDefinition = nem.utils.helpers.searchMosaicDefinitionArray(res.data, [yourMosaicName]);

        const fullMosaicName  = nem.utils.format.mosaicIdToName(yourMosaic.mosaicId);

        if (undefined === neededDefinition[fullMosaicName]) {
            return console.log('Mosaic not found !');
        }

        mosaicDefinitionMetaDataPair[fullMosaicName] = {};
        mosaicDefinitionMetaDataPair[fullMosaicName].mosaicDefinition = neededDefinition[fullMosaicName];

        nem.com.requests.mosaic.supply(endpoint, fullMosaicName).then(supplyRes => {

            mosaicDefinitionMetaDataPair['nem:xem'].supply = 8999999999;
            mosaicDefinitionMetaDataPair[fullMosaicName].supply = supplyRes.supply;

            const transactionEntity = nem.model.transactions.prepare('mosaicTransferTransaction')(common, transferTransaction, mosaicDefinitionMetaDataPair, nem.model.network.data.mainnet.id);

            nem.model.transactions.send(common, transactionEntity, endpoint).then(sendRes => {
                console.log('sendRes:', sendRes);
            }).catch(sendErr => {
                console.log('sendError:', sendErr);
            });
        }).catch(supplyErr => {
            console.log('supplyErr:', supplyErr);
        });
    }).catch(err => {
        console.log('mosaicDefinitionsError:', err);
    });
}

main();

$ node test.js
sendRes: { innerTransactionHash: {},
code: 1,
type: 1,
message: ‘SUCCESS’,
transactionHash:
{ data:
‘f08066a73d37f523482d6dc61a60e53db4cbd5097262f1ee419cae7ae4ad9a7a’ } }

送信結果

おおお、これをUIをつけてやりたい

<body>
	<div class="container">
		<h1 class="title">NEM Project</h1>
		<p>送金ボタンを押してください</p>
		<input type="button" value="送金" onclick="OnButtonClick();">
	</div>
	<script src="nem-sdk.js"></script>
	<script>
		var nem = require("nem-sdk").default;
		
		function OnButtonClick() {
			main();
			console.log("送金完了しました")
		}
		const endpoint = nem.model.objects.create('endpoint')(nem.model.nodes.defaultMainnet, nem.model.nodes.defaultPort);
		async function main() {
		    // 省略
		}
	</script>

あ、出来た^^

受け取るwalletのアドレスとメッセージを入力フォームにして、そこに送信できるようにしたい。

[NEM] NEM Walletから独自通貨(mosaic)を送金

Nem用のwalletであるRaccoon Walletをスマホにインストールし、ウォレットのアドレスを取得します。

RaccoonWallet
https://apps.apple.com/jp/app/raccoonwallet/id1437034062

NEM WalletからRaccoon Walletのアドレスへ、mosaicを送信します

Raccoon Wallet側で受け取ったトランザクションを確認

おおおお、なんか凄い
これをプログラムでやりたい。出来ればUI付きで

[Ethereum] UIをコントラクトに接続

$ mkdir greeter-dapp
$ truffle unbox react
$ truffle develop

truffle(develop)> compile
truffle(develop)> migrate

$ cp ../greeter/contracts/Greeter.sol contracts/

2_deploy_greeter.js

var GreeterContract = artifacts.require("./Greeter.sol");

module.exports = function(deployer) {
  deployer.deploy(GreeterContract);
};

client/src/App.js

import React, { Component } from "react";
import GreeterContract from "./contracts/Greeter.json";
import getWeb3 from "./getWeb3";

import "./App.css";

class App extends Component {
  state = { greeting: '', web3: null, accounts: null, contract: null };

  componentDidMount = async () => {
    try {
      // Get network provider and web3 instance.
      const web3 = await getWeb3();

      // Use web3 to get the user's accounts.
      const accounts = await web3.eth.getAccounts();

      // Get the contract instance.
      const networkId = await web3.eth.net.getId();
      const deployedNetwork = GreeterContract.networks[networkId];
      const instance = new web3.eth.Contract(
        GreeterContract.abi,
        deployedNetwork && deployedNetwork.address,
      );

      // Set web3, accounts, and contract to the state, and then proceed with an
      // example of interacting with the contract's methods.
      this.setState({ web3, accounts, contract: instance }, this.runExample);
    } catch (error) {
      // Catch any errors for any of the above operations.
      alert(
        `Failed to load web3, accounts, or contract. Check console for details.`,
      );
      console.error(error);
    }
  };

  runExample = async () => {
    const { accounts, contract } = this.state;

    const response = await contract.methods.greet().call();
    this.setState({greeting: response})
  };

  render() {
    if (!this.state.web3) {
      return <div>Loading Web3, accounts, and contract...</div>;
    }
    return (
      <div className="App">
        <h1>Greeter</h1>

        {this.state.greeting}

        <form>
          <label>
            New Greeting:
            <input type="text" value={this.state.greeting} onChange={this.handleGreetingChange}>
          </label>
        </form>
        <button onClick={this.formSubmitHandler}> Submit </button>
      </div>
    );
  }
}

export default App;

うーむ、ようわからん

[Ethereum] Web3を使ったスマートコントラクト

Web3はイーサリアムも操作できるようにするJSライブラリ
HTTPまたはIPC接続を使ってイサーリアムに接続するためのJSON-RPCラッパー
フロントエンド <-> Web3 <-> ブロックチェーン

### Web3のメソッド
getAccounts()
getBlockNumber()
getBalance()
sendTransaction()

web3.setProvider(provider) とする
web3ではPromiseを頻繁に使用する

metamaskはwe3を使っているサイトと簡単にやり取りができるブラウザ拡張
send
call(view/pure関数)

[Ethereum] テストプロジェクト FundraiserFactory

fundraiser_factory_test.js

const FundraiserFactoryContract = artifacts.require("FundraiserFactory");
const FundraiserContract = artifacts.require("Fundraiser");

contract("FundraiserFactory: deployment", ()=> {
	it("has been deployed", async() => {
		const fundraiserFactory = FundraiserFactoryContract.deployed();
		assert(fundraiserFactory, "fundraiser factory was not deployed");
	})
});

contract("FundraiserFactory: createFundraiser", (accounts) => {
	let fundraiserFactory;
	const name = "Beneficiary Name";
	const url = "beneficiaryname.org";
	const imageURL = "https://placekitten.com/600/350"
	const description = "Beneficiary Description"
	const beneficiary = accounts[1];

	it("increments the fundraisersCount", async() => {
		fundraiserFactory = await FundraiserFactoryContract.deployed();
		const currentFundraisersCount = fundraiserFactory.fundraisersCount();
		await fundraiserFactory.createFundraiser(
			name,
			url,
			imageURL,
			description,
			beneficiary
		);
		const newFundraisersCount = await fundraiserFactory.fundraisersCount();

		// assert.equal(
		// 	newFundraisersCount - currentFundraisersCount,
		// 	1,
		// 	"should increment by 1"
		// );
	});

	it("emits the FundraiserCreated event", async() => {
		fundraiserFactory = await FundraiserFactoryContract.deployed();
		const tx = await fundraiserFactory.createFundraiser(
			name,
			url,
			imageURL,
			description,
			beneficiary
		);
		const expectedEvent = "FundraiserCreated";
		const actualEvent = tx.logs[0].event;

		assert.equal(actualEvent, expectedEvent, "event should match");
	})

});

contract("FundraiserFactory: fundraisers", (accounts) => {
	async function createFundraiserFactory(fundraiserCount, accounts){
		const factory = await FundraiserFactoryContract.new();
		await addFundraisers(factory, fundraiserCount, accounts);
		return factory;
	}

	async function addFundraisers(factory, count, accounts){
		const name = "Beneficiary";
		const lowerCaseName = name.toLowerCase();
		const beneficiary = accounts[1];

		for (let i = 0; i < count; i++){
			await factory.createFundraiser(
				`${name} ${i}`,
				`${lowerCaseName}${i}.com`,
				`${lowerCaseName}${i}.png`,
				`Description for ${name} ${i}`,
				beneficiary
			);
		}
	}

	describe("when fundraisers collection is empty", () => {
		it("returns an empty collection", async() => {
			const factory = await createFundraiserFactory(0, accounts);
			const fundraisers = await factory.fundraisers(10, 0);
			assert.equal(
				fundraisers.length,
				0,
				"collection should be empty"
			);
		});
	});

	describe("varying limits", async() => {
		let factory;
		beforeEach(async() => {
			factory = await createFundraiserFactory(30, accounts);
		});

		it("returns 10 results when limit requested is 10", async()=> {
			const fundraisers = await factory.fundraisers(10, 0);
			assert.equal(
				fundraisers.length,
				10,
				"results size should be 10"
			);
		});
		xit("returns 20 results when limit requested is 20", async() => {
			const fundraisers = await factory.fundraisers(20, 0);
			assert.equal(
				fundraisers.length,
				20,
				"results size should be 20"
			);
		});
		xit("returns 20 results when limit requested is 30", async() => {
			const fundraisers = await factory.fundraisers(30, 0);
			assert.equal(
				fundraisers.length,
				20,
				"results size should be 20"
			);
		});

	});

	describe("varying offset", () => {
		let factory;
		beforeEach(async() => {
			factory = await createFundraiserFactory(10, accounts);
		});

		it("contains the fundraiser with the appropriate offset", async() => {
			const fundraisers = await factory.fundraisers(1, 0);
			const fundraiser = await FundraiserContract.at(fundraisers[0]);
			const name = await fundraiser.name();
			assert.ok(await name.includes(0), `${name} did not include the offset`);
		});

		it("contains the fundraiser with the appropriate offset", async() => {
			const fundraisers = await factory.fundraisers(1, 7);
			const fundraiser = await FundraiserContract.at(fundraisers[0]);
			const name = await fundraiser.name();
			assert.ok(await name.includes(7), `${name} did not include the offset`);
		})
	});

	describe("boundary conditions", ()=> {
		let factory;
		beforeEach(async() => {
			factory = await createFundraiserFactory(10, accounts);
		});

		it("raises out of bounds error", async () => {
			try {
				await factory.fundraisers(1, 11);
				assert.fail("error was not raised")
			} catch(err) {
				const expected = "offset out of bounds";
				assert.ok(err.message.includes(expected), `${err.message}`);
			}
		});

		it("adjusts return size to prevent out of bounds error", async() => {
			try {
				const fundraisers = await factory.fundraisers(10, 5);
				assert.equal(
					fundraisers.length,
					5,
					"collection adjusted"
				);
			} catch(err) {
				assert.fail("limit and offset exceeded bounds");
			}
		})
	})
})

contracts

pragma solidity >0.4.23 <=0.8.0;

import "./Fundraiser.sol";

contract FundraiserFactory {
	uint256 constant maxLimit = 20;
	Fundraiser[] private _fundraisers;

	event FundraiserCreated(Fundraiser indexed fundraiser, address indexed owner);

	function createFundraiser(
		string memory name,
		string memory url,
		string memory imageURL,
		string memory description,
		address payable beneficiary
	)

	public {
		Fundraiser fundraiser = new Fundraiser(
			name,
			url,
			imageURL,
			description,
			beneficiary,
			msg.sender
		);
		_fundraisers.push(fundraiser);
		emit FundraiserCreated(fundraiser, fundraiser.owner());
	}

	function fundraisersCount() public view returns(uint256) {
		return _fundraisers.length;
	}

	function fundraisers(uint256 limit, uint256 offset) public view returns(Fundraiser[] memory coll){

		require(offset <= fundraisersCount(), "offset out of bounds");

		uint256 size = fundraisersCount() - offset;
		size = size < limit ? size : limit;
		size = size < maxLimit ? size : maxLimit;
		coll = new Fundraiser[](size);

		for(uint256 i = 0; i < size; i++){
			coll[i] = _fundraisers[offset + i];
		}

		return coll;
	}
}

関数とその機能を覚えていけば、行けそうな気がして来た